added remaining required query params
This commit is contained in:
parent
f47e0b7cb0
commit
35ab852882
@ -3,4 +3,4 @@ module Main (main) where
|
|||||||
import Server
|
import Server
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = putStrLn "Try: http://localhost:8080/auth?scopes=[ID,Profile]" >> runMockServer 8080
|
main = putStrLn "Try: http://localhost:8080/auth?scope=[ID,Profile]&client_id=42&response_type=code&redirect_uri=localhost" >> runMockServer 8080
|
||||||
|
|||||||
@ -10,11 +10,12 @@ import User
|
|||||||
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import Control.Exception (bracket)
|
import Control.Exception (bracket)
|
||||||
|
import Control.Monad (unless)
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
|
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.List (find)
|
import Data.List (find)
|
||||||
import Data.Text hiding (find, head, map)
|
import Data.Text hiding (elem, find, head, map)
|
||||||
import Data.Text.Encoding (decodeUtf8)
|
import Data.Text.Encoding (decodeUtf8)
|
||||||
|
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
@ -24,31 +25,68 @@ import Network.Wai.Handler.Warp
|
|||||||
|
|
||||||
import Servant
|
import Servant
|
||||||
import Servant.Client
|
import Servant.Client
|
||||||
-- import Servant.API
|
import Servant.API
|
||||||
|
|
||||||
|
import Text.ParserCombinators.ReadPrec (look)
|
||||||
|
import Text.Read (readPrec)
|
||||||
|
|
||||||
|
|
||||||
testUsers :: [User]
|
testUsers :: [User] -- TODO move to db
|
||||||
testUsers =
|
testUsers =
|
||||||
[ User {name = "Fallback User", email = "foo@bar.com", password = "0000", uID = "0"}
|
[ User {name = "Fallback User", email = "foo@bar.com", password = "0000", uID = "0"}
|
||||||
, User {name = "Tina Tester", email = "t@t.tt", password = "1111", uID = "1"}
|
, User {name = "Tina Tester", email = "t@t.tt", password = "1111", uID = "1"}
|
||||||
, User {name = "Max Muster", email = "m@m.mm", password = "2222", uID = "2"}]
|
, User {name = "Max Muster", email = "m@m.mm", password = "2222", uID = "2"}]
|
||||||
|
|
||||||
|
trustedClients :: [Text] -- TODO move to db
|
||||||
|
trustedClients = ["42"]
|
||||||
|
|
||||||
|
data ResponseType = Code -- ^ authorisation code grant
|
||||||
|
| Token -- ^ implicit grant via access token
|
||||||
|
| IDToken -- ^ implicit grant via access token & ID token
|
||||||
|
deriving (Eq, Show)
|
||||||
|
instance Read ResponseType where
|
||||||
|
readPrec = look >>= \str -> return $ case str of
|
||||||
|
"code" -> Code
|
||||||
|
"token" -> Token
|
||||||
|
"id_token" -> IDToken
|
||||||
|
|
||||||
|
type QScope = String
|
||||||
|
type QClient = String
|
||||||
|
type QResType = String
|
||||||
|
type QRedirect = String
|
||||||
|
|
||||||
|
type QParam = QueryParam' [Required, Strict]
|
||||||
|
|
||||||
|
type Auth user userData = BasicAuth "login" user
|
||||||
|
:> "auth"
|
||||||
|
:> QParam "scope" QScope
|
||||||
|
:> QParam "client_id" QClient
|
||||||
|
:> QParam "response_type" QResType
|
||||||
|
:> QParam "redirect_uri" QRedirect
|
||||||
|
:> Get '[JSON] userData
|
||||||
|
|
||||||
type Auth user userData = BasicAuth "login" user :> "auth" :> QueryParam "scopes" String :> Get '[JSON] (Maybe userData) -- TODO also parametrise "auth" to (auth :: Symbol)
|
|
||||||
type Token = "token" :> Post '[JSON] Text -- TODO post jwt token
|
type Token = "token" :> Post '[JSON] Text -- TODO post jwt token
|
||||||
-- type Insert = "insert" :> Post '[JSON] User
|
-- type Insert = "insert" :> Post '[JSON] User
|
||||||
|
|
||||||
authServer :: forall user userData . UserData user userData => Server (Auth user userData)
|
authServer :: forall user userData . UserData user userData => Server (Auth user userData)
|
||||||
authServer = handleAuth
|
authServer = handleAuth
|
||||||
where
|
where
|
||||||
handleAuth :: user -> Maybe String -> Handler (Maybe userData)
|
handleAuth :: user
|
||||||
handleAuth _ Nothing = liftIO (putStrLn "no query param given") >> return Nothing
|
-> QScope
|
||||||
handleAuth u (Just x) = do
|
-> QClient
|
||||||
|
-> QResType
|
||||||
|
-> QRedirect
|
||||||
|
-> Handler userData
|
||||||
|
handleAuth u scopes client responseType url = do
|
||||||
|
unless (pack client `elem` trustedClients) . -- TODO fetch trusted clients from db
|
||||||
|
throwError $ err404 { errBody = "Not a trusted client."}
|
||||||
let
|
let
|
||||||
scopes = readScopes @user @userData x
|
scopes' = readScopes @user @userData scopes
|
||||||
ud = mconcat $ map (userScope @user @userData u) scopes
|
uData = mconcat $ map (userScope @user @userData u) scopes'
|
||||||
liftIO (putStrLn $ "query param: " ++ showScopes @user @userData scopes)
|
responseType' = read @ResponseType responseType
|
||||||
return $ Just ud
|
|
||||||
|
liftIO (putStrLn $ "user: " ++ show u ++ " | scopes: " ++ showScopes @user @userData scopes')
|
||||||
|
return uData
|
||||||
|
|
||||||
exampleAuthServer :: Server (Auth User (Map.Map Text Text))
|
exampleAuthServer :: Server (Auth User (Map.Map Text Text))
|
||||||
exampleAuthServer = authServer
|
exampleAuthServer = authServer
|
||||||
@ -71,8 +109,8 @@ authenticate users = BasicAuthCheck $ \authData -> do
|
|||||||
Nothing -> return NoSuchUser
|
Nothing -> return NoSuchUser
|
||||||
Just u -> return $ if uPass == password u then Authorized u else BadPassword
|
Just u -> return $ if uPass == password u then Authorized u else BadPassword
|
||||||
|
|
||||||
frontend :: BasicAuthData -> ClientM (Maybe (Map.Map Text Text))
|
frontend :: BasicAuthData -> ClientM (Map.Map Text Text)
|
||||||
frontend ba = client authAPI ba $ Just "[ID]"
|
frontend ba = client authAPI ba "[ID]" "42" "code" ""
|
||||||
|
|
||||||
runMockServer :: Int -> IO ()
|
runMockServer :: Int -> IO ()
|
||||||
runMockServer port = run port $ insecureOAuthMock' testUsers
|
runMockServer port = run port $ insecureOAuthMock' testUsers
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import Data.Text hiding (singleton)
|
|||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
|
|
||||||
|
|
||||||
class (Eq u, ToJSON a, Monoid a) => UserData u a where -- TODO Eq maybe not necessary, but currently needed for TypeApplications
|
class (Show u, ToJSON a, Monoid a) => UserData u a where -- TODO Show maybe not necessary, but currently needed for TypeApplications
|
||||||
data Scope u
|
data Scope u
|
||||||
readScopes :: String -> [Scope u]
|
readScopes :: String -> [Scope u]
|
||||||
showScopes :: [Scope u] -> String
|
showScopes :: [Scope u] -> String
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user