store active tokens & scopes
This commit is contained in:
parent
c7989034b4
commit
2716ccf2c0
@ -20,6 +20,7 @@ extra-source-files:
|
|||||||
library
|
library
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
AuthCode
|
AuthCode
|
||||||
|
DB
|
||||||
Server
|
Server
|
||||||
User
|
User
|
||||||
other-modules:
|
other-modules:
|
||||||
@ -45,6 +46,7 @@ library
|
|||||||
, text
|
, text
|
||||||
, time
|
, time
|
||||||
, transformers
|
, transformers
|
||||||
|
, uuid
|
||||||
, warp
|
, warp
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
@ -74,6 +76,7 @@ executable oauth2-mock-server-exe
|
|||||||
, text
|
, text
|
||||||
, time
|
, time
|
||||||
, transformers
|
, transformers
|
||||||
|
, uuid
|
||||||
, warp
|
, warp
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
@ -104,5 +107,6 @@ test-suite oauth2-mock-server-test
|
|||||||
, text
|
, text
|
||||||
, time
|
, time
|
||||||
, transformers
|
, transformers
|
||||||
|
, uuid
|
||||||
, warp
|
, warp
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|||||||
@ -36,6 +36,7 @@ dependencies:
|
|||||||
- jose-jwt
|
- jose-jwt
|
||||||
- base64
|
- base64
|
||||||
- http-api-data
|
- http-api-data
|
||||||
|
- uuid
|
||||||
|
|
||||||
ghc-options:
|
ghc-options:
|
||||||
- -Wall
|
- -Wall
|
||||||
|
|||||||
@ -1,17 +1,23 @@
|
|||||||
{-# LANGUAGE OverloadedRecordDot, OverloadedStrings #-}
|
{-# LANGUAGE OverloadedRecordDot, OverloadedStrings, ScopedTypeVariables #-}
|
||||||
|
|
||||||
module AuthCode
|
module AuthCode
|
||||||
( State (..)
|
( State(..)
|
||||||
, AuthState
|
, AuthState
|
||||||
|
, AuthRequest(..)
|
||||||
|
, JWT(..)
|
||||||
, genUnencryptedCode
|
, genUnencryptedCode
|
||||||
, verify
|
, verify
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import User
|
||||||
|
|
||||||
|
import Data.Aeson
|
||||||
import Data.Map.Strict (Map)
|
import Data.Map.Strict (Map)
|
||||||
import Data.Maybe (isJust, fromMaybe)
|
import Data.Maybe (isJust, fromMaybe)
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
import Data.Text (pack, replace, Text)
|
import Data.Text (pack, replace, Text)
|
||||||
import Data.Text.Encoding.Base64
|
import Data.Text.Encoding.Base64
|
||||||
|
import Data.UUID
|
||||||
|
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
|
|
||||||
@ -23,42 +29,62 @@ import Control.Monad.STM
|
|||||||
import Jose.Jwk (Jwk(..))
|
import Jose.Jwk (Jwk(..))
|
||||||
|
|
||||||
|
|
||||||
|
data JWT = JWT
|
||||||
|
{ issuer :: Text
|
||||||
|
, expiration :: UTCTime
|
||||||
|
, jti :: UUID
|
||||||
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance ToJSON JWT where
|
||||||
|
toJSON (JWT i e j) = object ["iss" .= i, "exp" .= e, "jti" .= j]
|
||||||
|
|
||||||
|
instance FromJSON JWT where
|
||||||
|
parseJSON (Object o) = JWT <$> o .: "iss" <*> o .: "exp" <*> o .: "jti"
|
||||||
|
|
||||||
|
|
||||||
data State = State
|
data AuthRequest user = AuthRequest
|
||||||
{ activeCodes :: Map Text (String, UTCTime) -- ^ maps auth codes to (client ID, expiration time)
|
{ client :: String
|
||||||
|
, codeExpiration :: NominalDiffTime
|
||||||
|
, user :: user
|
||||||
|
, scopes :: [Scope user]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
data State user = State
|
||||||
|
{ activeCodes :: Map Text (AuthRequest user)
|
||||||
|
, activeTokens :: Map UUID (user, [Scope user])
|
||||||
, publicKey :: Jwk
|
, publicKey :: Jwk
|
||||||
, privateKey :: Jwk
|
, privateKey :: Jwk
|
||||||
} deriving Show
|
}
|
||||||
|
|
||||||
type AuthState = TVar State
|
type AuthState user = TVar (State user)
|
||||||
|
|
||||||
genUnencryptedCode :: String
|
genUnencryptedCode :: AuthRequest user
|
||||||
-> String
|
-> String
|
||||||
-> NominalDiffTime
|
-> AuthState user
|
||||||
-> AuthState
|
|
||||||
-> IO (Maybe Text)
|
-> IO (Maybe Text)
|
||||||
genUnencryptedCode client url expiration state = do
|
genUnencryptedCode req url state = do
|
||||||
now <- getCurrentTime
|
now <- getCurrentTime
|
||||||
let
|
let
|
||||||
expiresAt = expiration `addUTCTime` now
|
expiresAt = req.codeExpiration `addUTCTime` now
|
||||||
simpleCode = replace "/" "%2F" . replace "=" "%3D" . encodeBase64 . pack . filter (/= ' ') $ client <> url <> show now <> show expiresAt
|
simpleCode = replace "/" "%2F" . replace "=" "%3D" . encodeBase64 . pack . filter (/= ' ') $ req.client <> url <> show now <> show expiresAt
|
||||||
success <- atomically . stateTVar state $ \s ->
|
success <- atomically . stateTVar state $ \s ->
|
||||||
let mEntry = M.lookup simpleCode s.activeCodes
|
let mEntry = M.lookup simpleCode s.activeCodes
|
||||||
in
|
in
|
||||||
if isJust mEntry
|
if isJust mEntry
|
||||||
then (False, s)
|
then (False, s)
|
||||||
else (True, s{ activeCodes = M.insert simpleCode (client, expiresAt) s.activeCodes })
|
else (True, s{ activeCodes = M.insert simpleCode req s.activeCodes })
|
||||||
if success then expire simpleCode expiration state >> return (Just simpleCode) else return Nothing
|
if success then expire simpleCode req.codeExpiration state >> return (Just simpleCode) else return Nothing
|
||||||
|
|
||||||
|
|
||||||
expire :: Text -> NominalDiffTime -> AuthState -> IO ()
|
expire :: Text -> NominalDiffTime -> AuthState user -> IO ()
|
||||||
expire code time state = void . forkIO $ do
|
expire code time state = void . forkIO $ do
|
||||||
threadDelay $ fromEnum time
|
threadDelay $ fromEnum time
|
||||||
atomically . modifyTVar state $ \s -> s{ activeCodes = M.delete code s.activeCodes }
|
atomically . modifyTVar state $ \s -> s{ activeCodes = M.delete code s.activeCodes }
|
||||||
|
|
||||||
|
|
||||||
verify :: Text -> Maybe String -> AuthState -> IO Bool
|
verify :: Text -> Maybe String -> AuthState user -> IO (Maybe (user, [Scope user]))
|
||||||
verify code mClientID state = do
|
verify code mClientID state = do
|
||||||
now <- getCurrentTime
|
now <- getCurrentTime
|
||||||
mData <- atomically $ do
|
mData <- atomically $ do
|
||||||
@ -66,5 +92,5 @@ verify code mClientID state = do
|
|||||||
modifyTVar state $ \s -> s{ activeCodes = M.delete code s.activeCodes }
|
modifyTVar state $ \s -> s{ activeCodes = M.delete code s.activeCodes }
|
||||||
return result
|
return result
|
||||||
return $ case mData of
|
return $ case mData of
|
||||||
Just (clientID', _) -> (fromMaybe clientID' mClientID) == clientID'
|
Just (AuthRequest clientID' _ u s) -> if (fromMaybe clientID' mClientID) == clientID' then Just (u, s) else Nothing
|
||||||
_ -> False
|
_ -> Nothing
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import User
|
|||||||
import Control.Applicative ((<|>))
|
import Control.Applicative ((<|>))
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import Control.Concurrent.STM (atomically)
|
import Control.Concurrent.STM (atomically)
|
||||||
import Control.Concurrent.STM.TVar (newTVarIO, readTVar)
|
import Control.Concurrent.STM.TVar (newTVarIO, readTVar, modifyTVar)
|
||||||
import Control.Exception (bracket)
|
import Control.Exception (bracket)
|
||||||
import Control.Monad (unless)
|
import Control.Monad (unless)
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
@ -26,6 +26,7 @@ import Data.String (IsString (..))
|
|||||||
import Data.Text hiding (elem, find, head, length, map, null, splitAt, tail, words)
|
import Data.Text hiding (elem, find, head, length, map, null, splitAt, tail, words)
|
||||||
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
|
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
|
||||||
import Data.Time.Clock (NominalDiffTime (..), nominalDay, UTCTime(..), getCurrentTime, addUTCTime)
|
import Data.Time.Clock (NominalDiffTime (..), nominalDay, UTCTime(..), getCurrentTime, addUTCTime)
|
||||||
|
import Data.UUID.V4
|
||||||
|
|
||||||
import qualified Data.ByteString.Char8 as BS
|
import qualified Data.ByteString.Char8 as BS
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
@ -103,13 +104,13 @@ type Auth user userData = BasicAuth "login" user
|
|||||||
-- type Insert = "insert" :> Post '[JSON] User
|
-- type Insert = "insert" :> Post '[JSON] User
|
||||||
|
|
||||||
|
|
||||||
type AuthHandler = ReaderT AuthState Handler
|
type AuthHandler user = ReaderT (AuthState user) Handler
|
||||||
type AuthServer a = ServerT a AuthHandler
|
type AuthServer user a = ServerT a (AuthHandler user)
|
||||||
|
|
||||||
toHandler :: AuthState -> AuthHandler a -> Handler a
|
toHandler :: forall user userData a . UserData user userData => AuthState user -> AuthHandler user a -> Handler a
|
||||||
toHandler s h = runReaderT h s
|
toHandler s h = runReaderT h s
|
||||||
|
|
||||||
authServer :: forall user userData . UserData user userData => AuthServer (Auth user userData)
|
authServer :: forall user userData . UserData user userData => AuthServer user (Auth user userData)
|
||||||
authServer = handleAuth
|
authServer = handleAuth
|
||||||
where
|
where
|
||||||
handleAuth :: user
|
handleAuth :: user
|
||||||
@ -118,18 +119,20 @@ authServer = handleAuth
|
|||||||
-> QResType
|
-> QResType
|
||||||
-> QRedirect
|
-> QRedirect
|
||||||
-> Maybe QState
|
-> Maybe QState
|
||||||
-> AuthHandler userData
|
-> AuthHandler user userData
|
||||||
handleAuth u scopes client responseType url mState = do
|
handleAuth u scopes client responseType url mState = do
|
||||||
unless (isJust $ find (\c -> ident c == pack client) trustedClients) . -- TODO fetch trusted clients from db | TODO also check if the redirect url really belongs to the client
|
unless (isJust $ find (\c -> ident c == pack client) trustedClients) . -- TODO fetch trusted clients from db | TODO also check if the redirect url really belongs to the client
|
||||||
throwError $ err404 { errBody = "Not a trusted client."}
|
throwError $ err404 { errBody = "Not a trusted client."}
|
||||||
let responseType' = read @ResponseType responseType
|
let
|
||||||
|
responseType' = read @ResponseType responseType
|
||||||
|
scopes' = map (readScope @user @userData) $ words scopes
|
||||||
liftIO $ print responseType'
|
liftIO $ print responseType'
|
||||||
unless (responseType' == Code) $ throwError err500 { errBody = "Unsupported response type" }
|
unless (responseType' == Code) $ throwError err500 { errBody = "Unsupported response type" }
|
||||||
mAuthCode <- asks (genUnencryptedCode client url 600) >>= liftIO
|
mAuthCode <- asks (genUnencryptedCode (AuthRequest client 600 u scopes') url) >>= liftIO
|
||||||
liftIO $ print mAuthCode
|
liftIO $ print mAuthCode
|
||||||
-- liftIO . putStrLn $ "user: " ++ show u ++ " | scopes: " ++ show (map (showScope @user @userData) scopes')
|
liftIO . putStrLn $ "user: " ++ show u ++ " | scopes: " ++ show (map (showScope @user @userData) scopes')
|
||||||
redirect $ addParams url mAuthCode mState
|
redirect $ addParams url mAuthCode mState
|
||||||
redirect :: Maybe ByteString -> AuthHandler userData
|
redirect :: Maybe ByteString -> AuthHandler user userData
|
||||||
redirect (Just url) = liftIO (print url) >> throwError err303 { errHeaders = [("Location", url)]}
|
redirect (Just url) = liftIO (print url) >> throwError err303 { errHeaders = [("Location", url)]}
|
||||||
redirect Nothing = throwError err500 { errBody = "Could not generate authorisation code."}
|
redirect Nothing = throwError err500 { errBody = "Could not generate authorisation code."}
|
||||||
addParams :: String -> Maybe Text -> Maybe Text -> Maybe ByteString
|
addParams :: String -> Maybe Text -> Maybe Text -> Maybe ByteString
|
||||||
@ -167,18 +170,6 @@ instance FromForm ClientData where
|
|||||||
<*> parseMaybe "redirect_uri" f
|
<*> parseMaybe "redirect_uri" f
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
data JWT = JWT
|
|
||||||
{ issuer :: Text
|
|
||||||
, expiration :: UTCTime
|
|
||||||
} deriving (Show, Eq)
|
|
||||||
|
|
||||||
instance ToJSON JWT where
|
|
||||||
toJSON (JWT i e) = object ["iss" .= i, "exp" .= e]
|
|
||||||
|
|
||||||
instance FromJSON JWT where
|
|
||||||
parseJSON (Object o) = JWT <$> o .: "iss" <*> o .: "exp"
|
|
||||||
|
|
||||||
data JWTWrapper = JWTW
|
data JWTWrapper = JWTW
|
||||||
{ token :: String
|
{ token :: String
|
||||||
, expiresIn :: NominalDiffTime
|
, expiresIn :: NominalDiffTime
|
||||||
@ -202,32 +193,37 @@ type Token = "token"
|
|||||||
:> Post '[JSON] JWTWrapper
|
:> Post '[JSON] JWTWrapper
|
||||||
|
|
||||||
|
|
||||||
tokenEndpoint :: AuthServer Token
|
tokenEndpoint :: forall user userData . UserData user userData => AuthServer user Token
|
||||||
tokenEndpoint = provideToken
|
tokenEndpoint = provideToken
|
||||||
where
|
where
|
||||||
provideToken :: ClientData -> AuthHandler JWTWrapper
|
provideToken :: ClientData -> AuthHandler user JWTWrapper
|
||||||
provideToken client = do
|
provideToken client = do
|
||||||
unless (isNothing (clientID client >> clientSecret client)
|
unless (isNothing (clientID client >> clientSecret client)
|
||||||
|| Client (pack . fromJust $ clientID client) (pack . fromJust $ clientSecret client) `elem` trustedClients) .
|
|| Client (pack . fromJust $ clientID client) (pack . fromJust $ clientSecret client) `elem` trustedClients) .
|
||||||
throwError $ err500 { errBody = "Invalid client" }
|
throwError $ err500 { errBody = "Invalid client" }
|
||||||
valid <- asks (verify (pack $ authCode client) (clientID client)) >>= liftIO -- TODO verify redirect url here
|
mUser <- asks (verify (pack $ authCode client) (clientID client)) >>= liftIO -- TODO verify redirect url here
|
||||||
unless valid . throwError $ err500 { errBody = "Invalid authorisation code" }
|
unless (isJust mUser) . throwError $ err500 { errBody = "Invalid authorisation code" }
|
||||||
-- return JWT {token = "", tokenType = "JWT", expiration = 0.25 * nominalDay}
|
-- return JWT {token = "", tokenType = "JWT", expiration = 0.25 * nominalDay}
|
||||||
token <- asks mkToken >>= liftIO
|
let (user, scopes) = fromJust mUser
|
||||||
|
token <- asks (mkToken @user @userData user scopes) >>= liftIO
|
||||||
liftIO . putStrLn $ "token: " ++ show token
|
liftIO . putStrLn $ "token: " ++ show token
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
mkToken :: AuthState -> IO JWTWrapper
|
mkToken :: forall user userData . UserData user userData
|
||||||
mkToken state = do
|
=> user -> [Scope user] -> AuthState user -> IO JWTWrapper
|
||||||
|
mkToken u scopes state = do
|
||||||
pubKey <- atomically $ readTVar state >>= return . publicKey
|
pubKey <- atomically $ readTVar state >>= return . publicKey
|
||||||
now <- getCurrentTime
|
now <- getCurrentTime
|
||||||
|
uuid <- nextRandom
|
||||||
let
|
let
|
||||||
lifetime = nominalDay / 4 -- TODO make configurable
|
lifetime = nominalDay / 24 -- TODO make configurable
|
||||||
jwt = JWT "Oauth2MockServer" (lifetime `addUTCTime` now)
|
jwt = JWT "Oauth2MockServer" (lifetime `addUTCTime` now) uuid
|
||||||
encoded <- jwkEncode RSA_OAEP_256 A128GCM pubKey (Nested . Jwt . toStrict $ encode jwt)
|
encoded <- jwkEncode RSA_OAEP_256 A128GCM pubKey (Nested . Jwt . toStrict $ encode jwt)
|
||||||
case encoded of
|
case encoded of
|
||||||
Right (Jwt token) -> return $ JWTW (BS.unpack token) lifetime
|
Right (Jwt token) -> do
|
||||||
|
atomically . modifyTVar state $ \s -> s { activeTokens = Map.insert uuid (u, scopes) (activeTokens s) }
|
||||||
|
return $ JWTW (BS.unpack token) lifetime
|
||||||
Left e -> error $ show e
|
Left e -> error $ show e
|
||||||
|
|
||||||
|
|
||||||
@ -250,20 +246,21 @@ type UserList userData = Users
|
|||||||
:> Get '[JSON] [userData] -- TODO support query params
|
:> Get '[JSON] [userData] -- TODO support query params
|
||||||
|
|
||||||
|
|
||||||
userEndpoint :: forall user userData . UserData user userData => AuthServer (Me userData)
|
userEndpoint :: forall user userData . UserData user userData => AuthServer user (Me userData)
|
||||||
userEndpoint = handleUserData
|
userEndpoint = handleUserData
|
||||||
where
|
where
|
||||||
handleUserData :: Text -> AuthHandler userData
|
handleUserData :: Text -> AuthHandler user userData
|
||||||
handleUserData jwtw = do
|
handleUserData jwtw = do
|
||||||
let mToken = stripPrefix "Bearer " jwtw
|
let mToken = stripPrefix "Bearer " jwtw
|
||||||
unless (isJust mToken) . throwError $ err500 { errBody = "Invalid token format"}
|
unless (isJust mToken) . throwError $ err500 { errBody = "Invalid token format"}
|
||||||
token <- asks (decodeToken (fromJust mToken)) >>= liftIO
|
token <- asks (decodeToken @user @userData (fromJust mToken)) >>= liftIO
|
||||||
liftIO $ putStrLn "decoded token:" >> print token
|
liftIO $ putStrLn "decoded token:" >> print token
|
||||||
case token of
|
case token of
|
||||||
Left e -> throwError $ err500 { errBody = fromString $ show e }
|
Left e -> throwError $ err500 { errBody = fromString $ show e }
|
||||||
Right (Jwe (header, body)) -> do
|
Right (Jwe (header, body)) -> do
|
||||||
let jwt = fromJust . decode @JWT $ fromStrict body
|
let jwt = fromJust . decode @JWT $ fromStrict body
|
||||||
-- TODO check if token grants access, then read logged in user from cookie
|
-- TODO check if token grants access, then read logged in user from cookie
|
||||||
|
liftIO $ print jwt
|
||||||
return mempty
|
return mempty
|
||||||
-- let
|
-- let
|
||||||
-- scopes' = map (readScope @user @userData) $ words scopes
|
-- scopes' = map (readScope @user @userData) $ words scopes
|
||||||
@ -271,15 +268,15 @@ userEndpoint = handleUserData
|
|||||||
-- liftIO . putStrLn $ "user: " ++ show u ++ " | scopes: " ++ show (map (showScope @user @userData) scopes')
|
-- liftIO . putStrLn $ "user: " ++ show u ++ " | scopes: " ++ show (map (showScope @user @userData) scopes')
|
||||||
-- return uData
|
-- return uData
|
||||||
|
|
||||||
decodeToken :: Text -> AuthState -> IO (Either JwtError JwtContent)
|
decodeToken :: forall user userData . UserData user userData => Text -> AuthState user -> IO (Either JwtError JwtContent)
|
||||||
decodeToken token state = do
|
decodeToken token state = do
|
||||||
prKey <- atomically $ readTVar state >>= return . privateKey
|
prKey <- atomically $ readTVar state >>= return . privateKey
|
||||||
jwkDecode prKey $ encodeUtf8 token
|
jwkDecode prKey $ encodeUtf8 token
|
||||||
|
|
||||||
userListEndpoint :: forall user userData . UserData user userData => AuthServer (UserList userData)
|
userListEndpoint :: forall user userData . UserData user userData => AuthServer user (UserList userData)
|
||||||
userListEndpoint = handleUserData
|
userListEndpoint = handleUserData
|
||||||
where
|
where
|
||||||
handleUserData :: Text -> AuthHandler [userData]
|
handleUserData :: Text -> AuthHandler user [userData]
|
||||||
handleUserData jwtw = do
|
handleUserData jwtw = do
|
||||||
undefined
|
undefined
|
||||||
|
|
||||||
@ -293,13 +290,13 @@ type Routing user userData = Auth user userData
|
|||||||
:<|> Me userData
|
:<|> Me userData
|
||||||
:<|> UserList userData
|
:<|> UserList userData
|
||||||
|
|
||||||
routing :: forall user userData . UserData user userData => AuthServer (Routing user userData)
|
routing :: forall user userData . UserData user userData => AuthServer user (Routing user userData)
|
||||||
routing = authServer @user @userData
|
routing = authServer @user @userData
|
||||||
:<|> tokenEndpoint
|
:<|> tokenEndpoint @user @userData
|
||||||
:<|> userEndpoint @user @userData
|
:<|> userEndpoint @user @userData
|
||||||
:<|> userListEndpoint @user @userData
|
:<|> userListEndpoint @user @userData
|
||||||
|
|
||||||
exampleAuthServer :: AuthServer (Routing User (Map.Map Text Text))
|
exampleAuthServer :: AuthServer User (Routing User (Map.Map Text Text))
|
||||||
exampleAuthServer = routing
|
exampleAuthServer = routing
|
||||||
|
|
||||||
|
|
||||||
@ -309,8 +306,8 @@ authAPI = Proxy
|
|||||||
-- insecureOAuthMock :: Application
|
-- insecureOAuthMock :: Application
|
||||||
-- insecureOAuthMock = authAPI `serve` exampleAuthServer
|
-- insecureOAuthMock = authAPI `serve` exampleAuthServer
|
||||||
|
|
||||||
insecureOAuthMock' :: [User] -> AuthState -> Application
|
insecureOAuthMock' :: [User] -> AuthState User -> Application
|
||||||
insecureOAuthMock' testUsers s = serveWithContext authAPI c $ hoistServerWithContext authAPI p (toHandler s) exampleAuthServer
|
insecureOAuthMock' testUsers s = serveWithContext authAPI c $ hoistServerWithContext authAPI p (toHandler @User @(Map.Map Text Text) s) exampleAuthServer
|
||||||
where
|
where
|
||||||
c = authenticate testUsers :. EmptyContext
|
c = authenticate testUsers :. EmptyContext
|
||||||
p = Proxy :: Proxy '[BasicAuthCheck User]
|
p = Proxy :: Proxy '[BasicAuthCheck User]
|
||||||
@ -328,7 +325,7 @@ authenticate users = BasicAuthCheck $ \authData -> do
|
|||||||
|
|
||||||
runMockServer :: Int -> IO ()
|
runMockServer :: Int -> IO ()
|
||||||
runMockServer port = do
|
runMockServer port = do
|
||||||
state <- mkState
|
state <- mkState @User @(Map.Map Text Text)
|
||||||
run port $ insecureOAuthMock' testUsers state
|
run port $ insecureOAuthMock' testUsers state
|
||||||
|
|
||||||
-- runMockServer' :: Int -> IO ()
|
-- runMockServer' :: Int -> IO ()
|
||||||
@ -339,9 +336,11 @@ runMockServer port = do
|
|||||||
-- runClientM (frontend $ BasicAuthData "foo@bar.com" "0000") (mkClientEnv mgr (BaseUrl Http "localhost" port ""))
|
-- runClientM (frontend $ BasicAuthData "foo@bar.com" "0000") (mkClientEnv mgr (BaseUrl Http "localhost" port ""))
|
||||||
-- >>= print
|
-- >>= print
|
||||||
|
|
||||||
mkState :: IO AuthState
|
mkState :: forall user userData . UserData user userData => IO (AuthState user)
|
||||||
mkState = do
|
mkState = do
|
||||||
(publicKey, privateKey) <- generateRsaKeyPair 256 (KeyId "Oauth2MockKey") Enc Nothing
|
(publicKey, privateKey) <- generateRsaKeyPair 256 (KeyId "Oauth2MockKey") Enc Nothing
|
||||||
let activeCodes = Map.empty
|
let
|
||||||
|
activeCodes = Map.empty
|
||||||
|
activeTokens = Map.empty
|
||||||
newTVarIO State{..}
|
newTVarIO State{..}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user