bloodhound-1.0.0.0: tests/Test/SecurityRoleMappingsSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Test.SecurityRoleMappingsSpec (spec) where
import Data.Aeson
import Data.Aeson.KeyMap qualified as KM
import Data.ByteString.Lazy.Char8 qualified as L
import TestsUtils.Import
import Prelude
-- | A role mapping with a nested @any -> all -> field@ rule tree.
sampleMappingBytes :: L.ByteString
sampleMappingBytes =
"{\
\ \"enabled\": true,\
\ \"roles\": [\"admin\"],\
\ \"rules\": {\
\ \"any\": [\
\ {\"field\": {\"username\": \"alice\"}},\
\ {\"all\": [\
\ {\"field\": {\"realm.name\": \"ad\"}},\
\ {\"field\": {\"groups\": \"cn=admins\"}}\
\ ]}\
\ ]\
\ },\
\ \"metadata\": {\"version\": 1}\
\}"
-- | A mapping using the @except@ composite rule.
sampleExceptMappingBytes :: L.ByteString
sampleExceptMappingBytes =
"{\
\ \"roles\": [\"user\"],\
\ \"rules\": {\"except\": {\"field\": {\"username\": \"blacklist\"}}}\
\}"
spec :: Spec
spec = do
describe "RoleMapping" $ do
it "decodes a nested any/all/field rule tree" $ do
let Just decoded = decode sampleMappingBytes :: Maybe RoleMapping
romEnabled decoded `shouldBe` Just True
romRoles decoded `shouldBe` [RoleName "admin"]
-- The top rule is an @any@ over two branches.
case romRules decoded of
RuleAny branches ->
length (branches) `shouldBe` 2
other -> expectationFailure ("expected RuleAny, got " <> show other)
-- Stable round-trip.
let Just rt = decode (encode decoded) :: Maybe RoleMapping
romRoles rt `shouldBe` [RoleName "admin"]
it "decodes the except composite rule" $ do
let Just decoded = decode sampleExceptMappingBytes :: Maybe RoleMapping
case romRules decoded of
RuleExcept (RuleField km) ->
KM.lookup "username" km `shouldSatisfy` isJust
other -> expectationFailure ("expected RuleExcept (RuleField), got " <> show other)
it "encodes a field rule as {field: {...}}" $ do
let rule = RuleField (KM.singleton "dn" "CN=alice")
decode (encode rule) `shouldBe` Just (rule :: RoleMappingRule)
describe "RoleMappingRule" $ do
it "rejects an empty object" $ do
decode "{}" `shouldBe` (Nothing :: Maybe RoleMappingRule)
it "preserves an unknown rule kind verbatim" $ do
let decoded = decode "{\"future_rule\":{\"x\":1}}" :: Maybe RoleMappingRule
decoded `shouldSatisfy` isJust
case decoded of
Just (RuleCustom _ _) -> True `shouldBe` True
other -> expectationFailure ("expected RuleCustom, got " <> show other)
describe "RoleMappingsListResponse" $ do
it "decodes an object keyed by mapping name" $ do
let bytes =
"{\
\ \"mapping1\": {\
\ \"roles\": [\"admin\"],\
\ \"rules\": {\"field\": {\"username\": \"x\"}}\
\ }\
\}"
let Just resp = decode bytes :: Maybe RoleMappingsListResponse
length (roleMappingsListEntries resp) `shouldBe` 1