bloodhound-1.0.0.0: tests/Test/SecurityAuthenticateSpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Test.SecurityAuthenticateSpec (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
-- | @GET /_security/_authenticate@ response for the reserved @elastic@
-- user, including an @api_key@ sibling that should survive in 'authExtras'.
sampleAuthenticateBytes :: L.ByteString
sampleAuthenticateBytes =
"{\
\ \"username\": \"elastic\",\
\ \"roles\": [\"superuser\"],\
\ \"full_name\": null,\
\ \"email\": null,\
\ \"metadata\": {\"_reserved\": true},\
\ \"enabled\": true,\
\ \"authentication_realm\": {\"name\": \"reserved\", \"type\": \"reserved\"},\
\ \"lookup_realm\": {\"name\": \"reserved\", \"type\": \"reserved\"},\
\ \"authentication_provider\": \"reserved\",\
\ \"principal\": \"elastic\",\
\ \"api_key\": {\"id\": \"k1\", \"name\": \"key\"}\
\}"
-- | @GET /_security/_whoami@ response (ES 7.16+) carrying the optional
-- @principal@ / @delegate@ fields.
sampleWhoAmIBytes :: L.ByteString
sampleWhoAmIBytes =
"{\
\ \"username\": \"radmin\",\
\ \"roles\": [\"superuser\"],\
\ \"principal\": \"radmin\",\
\ \"delegate\": false,\
\ \"authentication_realm\": {\"name\": \"file\", \"type\": \"file\"},\
\ \"lookup_realm\": {\"name\": \"file\", \"type\": \"file\"}\
\}"
spec :: Spec
spec = do
describe "AuthenticateResponse" $ do
it "decodes username, roles, realms, provider, principal" $ do
let Just r = decode sampleAuthenticateBytes :: Maybe AuthenticateResponse
authUsername r `shouldBe` "elastic"
authRoles r `shouldBe` [RoleName "superuser"]
authEnabled r `shouldBe` Just True
authAuthenticationProvider r `shouldBe` Just "reserved"
authPrincipal r `shouldBe` Just "elastic"
case authAuthenticationRealm r of
Just realm -> do
srName realm `shouldBe` Just "reserved"
srType realm `shouldBe` Just "reserved"
Nothing -> expectationFailure "expected an authentication_realm"
it "preserves unknown sibling fields (api_key) in extras and round-trips" $ do
let Just r = decode sampleAuthenticateBytes :: Maybe AuthenticateResponse
KM.lookup "api_key" (authExtras r) `shouldSatisfy` isJust
let Just rt = decode (encode r) :: Maybe AuthenticateResponse
KM.lookup "api_key" (authExtras rt) `shouldSatisfy` isJust
it "tolerates a minimal response (just username)" $ do
let Just r = decode "{\"username\":\"u\"}" :: Maybe AuthenticateResponse
authUsername r `shouldBe` "u"
authRoles r `shouldBe` []
authAuthenticationRealm r `shouldBe` Nothing
describe "WhoAmIResponse" $ do
it "decodes principal / delegate / realms" $ do
let Just resp = decode sampleWhoAmIBytes :: Maybe WhoAmIResponse
wmUsername resp `shouldBe` "radmin"
wmPrincipal resp `shouldBe` Just "radmin"
wmDelegate resp `shouldBe` Just False
case wmAuthenticationRealm resp of
SecurityRealm {..} -> do
srName `shouldBe` Just "file"
srType `shouldBe` Just "file"
it "tolerates an absent delegate / principal / lookup_realm" $ do
let bytes =
"{\
\ \"username\": \"x\",\
\ \"roles\": [],\
\ \"authentication_realm\": {\"name\":\"n\",\"type\":\"t\"}\
\}"
let Just resp = decode bytes :: Maybe WhoAmIResponse
wmPrincipal resp `shouldBe` Nothing
wmDelegate resp `shouldBe` Nothing
wmLookupRealm resp `shouldBe` Nothing
it "round-trips" $ do
let Just resp = decode sampleWhoAmIBytes :: Maybe WhoAmIResponse
let Just rt = decode (encode resp) :: Maybe WhoAmIResponse
wmUsername rt `shouldBe` wmUsername resp
wmDelegate rt `shouldBe` wmDelegate resp
describe "LogoutRequest" $ do
it "encodes the token and omits an absent refresh_token" $ do
encode (defaultLogoutRequest "abc123") `shouldBe` "{\"token\":\"abc123\"}"
it "round-trips with an optional refresh_token" $ do
let req =
(defaultLogoutRequest "abc123")
{ lrRefreshToken = Just "rt456"
}
let Just rt = decode (encode req) :: Maybe LogoutRequest
lrToken rt `shouldBe` "abc123"
lrRefreshToken rt `shouldBe` Just "rt456"
describe "LogoutResponse" $ do
it "decodes {changed: true}" $ do
let Just resp = decode "{\"changed\":true}" :: Maybe LogoutResponse
loChanged resp `shouldBe` True
it "decodes {changed: false}" $ do
let Just resp = decode "{\"changed\":false}" :: Maybe LogoutResponse
loChanged resp `shouldBe` False
it "round-trips" $ do
let resp = LogoutResponse {loChanged = True}
decode (encode resp) `shouldBe` Just resp