access-token-provider-0.1.0.0: tests/Security/AccessTokenProvider/Internal/Providers/Test.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Security.AccessTokenProvider.Internal.Providers.Test
( securityAccessTokenProviderInternalProvidersTest
) where
import Control.Exception.Safe
import Control.Lens
import Control.Monad.IO.Class
import qualified Data.ByteString.Lazy as ByteString.Lazy
import Data.Format
import qualified Data.Map.Strict as Map
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import Data.UUID (UUID)
import Katip
import Network.HTTP.Client.Internal
import Network.HTTP.Types.Status
import Network.HTTP.Types.Version
import System.Random
import Test.Tasty
import Test.Tasty.HUnit
import UnliftIO.Concurrent
import Security.AccessTokenProvider
import qualified Security.AccessTokenProvider as ATP
import Security.AccessTokenProvider.Internal.Util
import Test
securityAccessTokenProviderInternalProvidersTest :: [TestTree]
securityAccessTokenProviderInternalProvidersTest =
[ testGroup "Security.AccessTokenProvider.Internal.Providers"
[ testCase "Fixed Provider reads from TOKEN"
fixedProviderReadsFromToken
, testCase "Fixed Provider reads from ATP_CONF"
fixedProviderReadsFromConf
, testCase "Fixed Provider reads from ATP_CONF and lookup fails"
fixedProviderReadsFromConfLookupFails
, testCase "File Provider reads from TOKEN_FILE"
fileProviderReadsFromTokenFile
, testCase "File Provider reads from ATP_CONF"
fileProviderReadsFromConf
, testCase "File Provider reads from ATP_CONF and lookup fails"
fileProviderReadsFromConfLookupFails
, testCase "Ropcg Provider reads from ATP_CONF"
ropcgProviderReadsFromConf
]
]
fixedProviderReadsFromToken :: Assertion
fixedProviderReadsFromToken = do
token <- tshow <$> (randomIO :: IO UUID)
let testState = TestState
{ _testStateFilesystem = Map.empty
, _testStateEnvironment = Map.fromList [ ("TOKEN", token) ]
, _testStateHttpResponse = Nothing
, _testStateHttpRequests = []
}
evalTestStack testState $ do
tokenProvider <- new (AccessTokenName "some-random-token-name")
(AccessToken token') <- retrieveAccessToken tokenProvider
liftIO $ token @=? token'
fixedProviderReadsFromConf :: Assertion
fixedProviderReadsFromConf = do
token <- tshow <$> (randomIO :: IO UUID)
let conf = [fmt|{"provider": "fixed", "tokens": {"label1": "$token"}}|]
testState = TestState
{ _testStateFilesystem = Map.empty
, _testStateEnvironment = Map.fromList [ ("ATP_CONF", conf) ]
, _testStateHttpResponse = Nothing
, _testStateHttpRequests = []
}
evalTestStack testState $ do
tokenProvider <- new (AccessTokenName "label1")
(AccessToken token') <- retrieveAccessToken tokenProvider
liftIO $ token @=? token'
fixedProviderReadsFromConfLookupFails :: Assertion
fixedProviderReadsFromConfLookupFails = do
token <- tshow <$> (randomIO :: IO UUID)
let conf = [fmt|{"provider": "fixed", "tokens": {"label1": "$token"}}|]
testState = TestState
{ _testStateFilesystem = Map.empty
, _testStateEnvironment = Map.fromList [ ("ATP_CONF", conf) ]
, _testStateHttpResponse = Nothing
, _testStateHttpRequests = []
}
evalTestStack testState $ do
Left _ <- tryAny $ new (AccessTokenName "label2")
pure ()
fileProviderReadsFromTokenFile :: Assertion
fileProviderReadsFromTokenFile = do
tokenText <- tshow <$> (randomIO :: IO UUID)
let tokenBytes = Text.encodeUtf8 tokenText
filename = "/a/b/c"
testState = TestState
{ _testStateFilesystem =
Map.fromList [ (filename, tokenBytes) ]
, _testStateEnvironment =
Map.fromList [ ("TOKEN_FILE", Text.pack filename) ]
, _testStateHttpResponse = Nothing
, _testStateHttpRequests = []
}
evalTestStack testState $ do
tokenProvider <- new (AccessTokenName "some-random-token-name")
(AccessToken token') <- retrieveAccessToken tokenProvider
liftIO $ tokenText @=? token'
fileProviderReadsFromConf :: Assertion
fileProviderReadsFromConf = do
tokenText <- tshow <$> (randomIO :: IO UUID)
let tokenBytes = Text.encodeUtf8 tokenText
filename = "/a/b/c"
conf = [fmt|{"provider": "file", "tokens": {"label1": "$filename"}}|]
testState = TestState
{ _testStateFilesystem =
Map.fromList [ (filename, tokenBytes) ]
, _testStateEnvironment =
Map.fromList [ ("ATP_CONF", conf) ]
, _testStateHttpResponse = Nothing
, _testStateHttpRequests = []
}
evalTestStack testState $ do
tokenProvider <- new (AccessTokenName "label1")
(AccessToken token') <- retrieveAccessToken tokenProvider
liftIO $ tokenText @=? token'
fileProviderReadsFromConfLookupFails :: Assertion
fileProviderReadsFromConfLookupFails = do
tokenText <- tshow <$> (randomIO :: IO UUID)
let tokenBytes = Text.encodeUtf8 tokenText
filename = "/a/b/c"
conf = [fmt|{"provider": "file", "tokens": {"label1": "$filename"}}|]
testState = TestState
{ _testStateFilesystem =
Map.fromList [ (filename, tokenBytes) ]
, _testStateEnvironment =
Map.fromList [ ("ATP_CONF", conf) ]
, _testStateHttpResponse = Nothing
, _testStateHttpRequests = []
}
evalTestStack testState $ do
Left _ <- tryAny $ new (AccessTokenName "label2")
pure ()
ropcgProviderReadsFromConf :: Assertion
ropcgProviderReadsFromConf = do
tokenText <- tshow <$> (randomIO :: IO UUID)
let conf = [fmt|{ "provider": "ropcg",
"credentials_directory": "/credentials",
"auth_endpoint": "https://localhost",
"tokens": {"label1": {"scopes": ["foo"]}}
}|]
responseBody = ByteString.Lazy.fromStrict . Text.encodeUtf8 $
[fmt|{"scope": "foo",
"expires_in": 60,
"token_type": "test",
"access_token": "$tokenText"
}|]
response = Response { responseStatus = ok200
, responseVersion = http20
, responseHeaders = []
, responseBody = responseBody
, responseCookieJar = CJ []
, responseClose' = ResponseClose (pure ())
}
userCredentials =
"{ \"application_username\": \"some-application-username\", \
\ \"application_password\": \"some-application-password\" }"
clientCredentials =
"{ \"client_id\": \"some-client-id\", \
\ \"client_secret\": \"some-client-secret\" }"
testState = TestState
{ _testStateFilesystem = Map.fromList
[ ("/credentials/user.json", userCredentials)
, ("/credentials/client.json", clientCredentials)
]
, _testStateEnvironment = Map.fromList [ ("ATP_CONF", conf) ]
, _testStateHttpResponse = Just response
, _testStateHttpRequests = []
}
(_, testState') <- runTestStack testState $ do
tokenProvider <- new (AccessTokenName "label1")
(AccessToken token) <- retrieveAccessToken tokenProvider
liftIO $ tokenText @=? token
pure ()
1 @=? length (testState'^.testStateHttpRequests)
pure ()
retrieveSomeToken :: KatipContextT IO ()
retrieveSomeToken = do
tokenProvider <- ATP.new (AccessTokenName "token-name")
token <- ATP.retrieveAccessToken tokenProvider
liftIO $ print token