changed token endpoint mimetype
This commit is contained in:
parent
0a2f1ab5dd
commit
93093d86e4
@ -35,6 +35,7 @@ library
|
|||||||
, base64
|
, base64
|
||||||
, bytestring
|
, bytestring
|
||||||
, containers
|
, containers
|
||||||
|
, http-api-data
|
||||||
, http-client
|
, http-client
|
||||||
, jose-jwt
|
, jose-jwt
|
||||||
, servant
|
, servant
|
||||||
@ -62,6 +63,7 @@ executable oauth2-mock-server-exe
|
|||||||
, base64
|
, base64
|
||||||
, bytestring
|
, bytestring
|
||||||
, containers
|
, containers
|
||||||
|
, http-api-data
|
||||||
, http-client
|
, http-client
|
||||||
, jose-jwt
|
, jose-jwt
|
||||||
, oauth2-mock-server
|
, oauth2-mock-server
|
||||||
@ -91,6 +93,7 @@ test-suite oauth2-mock-server-test
|
|||||||
, base64
|
, base64
|
||||||
, bytestring
|
, bytestring
|
||||||
, containers
|
, containers
|
||||||
|
, http-api-data
|
||||||
, http-client
|
, http-client
|
||||||
, jose-jwt
|
, jose-jwt
|
||||||
, oauth2-mock-server
|
, oauth2-mock-server
|
||||||
|
|||||||
@ -35,6 +35,7 @@ dependencies:
|
|||||||
- bytestring
|
- bytestring
|
||||||
- jose-jwt
|
- jose-jwt
|
||||||
- base64
|
- base64
|
||||||
|
- http-api-data
|
||||||
|
|
||||||
ghc-options:
|
ghc-options:
|
||||||
- -Wall
|
- -Wall
|
||||||
|
|||||||
@ -8,7 +8,7 @@ module AuthCode
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Map.Strict (Map)
|
import Data.Map.Strict (Map)
|
||||||
import Data.Maybe (isJust)
|
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
|
||||||
@ -58,13 +58,13 @@ expire code time state = void . forkIO $ do
|
|||||||
atomically . modifyTVar state $ \s -> s{ activeCodes = M.delete code s.activeCodes }
|
atomically . modifyTVar state $ \s -> s{ activeCodes = M.delete code s.activeCodes }
|
||||||
|
|
||||||
|
|
||||||
verify :: Text -> String -> AuthState -> IO Bool
|
verify :: Text -> Maybe String -> AuthState -> IO Bool
|
||||||
verify code clientID state = do
|
verify code mClientID state = do
|
||||||
now <- getCurrentTime
|
now <- getCurrentTime
|
||||||
mData <- atomically $ do
|
mData <- atomically $ do
|
||||||
result <- (readTVar >=> return . M.lookup code . activeCodes) state
|
result <- (readTVar >=> return . M.lookup code . activeCodes) state
|
||||||
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', _) -> clientID == clientID'
|
Just (clientID', _) -> (fromMaybe clientID' mClientID) == clientID'
|
||||||
_ -> False
|
_ -> False
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import Control.Monad.Trans.Reader
|
|||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.ByteString (ByteString (..), fromStrict, toStrict)
|
import Data.ByteString (ByteString (..), fromStrict, toStrict)
|
||||||
import Data.List (find, elemIndex)
|
import Data.List (find, elemIndex)
|
||||||
import Data.Maybe (fromMaybe, isJust)
|
import Data.Maybe (fromMaybe, fromJust, isJust, isNothing)
|
||||||
import Data.String (IsString (..))
|
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)
|
import Data.Text.Encoding (decodeUtf8)
|
||||||
@ -48,6 +48,8 @@ import Text.ParserCombinators.ReadPrec (look, pfail)
|
|||||||
|
|
||||||
import qualified Text.Read.Lex as Lex
|
import qualified Text.Read.Lex as Lex
|
||||||
|
|
||||||
|
import Web.Internal.FormUrlEncoded (FromForm(..), parseUnique, parseMaybe)
|
||||||
|
|
||||||
|
|
||||||
testUsers :: [User] -- TODO move to db
|
testUsers :: [User] -- TODO move to db
|
||||||
testUsers =
|
testUsers =
|
||||||
@ -149,23 +151,24 @@ data ClientData = ClientData
|
|||||||
{ grantType :: GrantType
|
{ grantType :: GrantType
|
||||||
, grant :: String
|
, grant :: String
|
||||||
, userName :: Maybe String
|
, userName :: Maybe String
|
||||||
, clientID :: String
|
, clientID :: Maybe String
|
||||||
, clientSecret :: String
|
, clientSecret :: Maybe String
|
||||||
, redirect :: Maybe String
|
, redirect :: Maybe String
|
||||||
} deriving Show
|
} deriving Show
|
||||||
|
|
||||||
instance FromJSON ClientData where
|
|
||||||
parseJSON (Object o) = ClientData
|
instance FromForm ClientData where
|
||||||
<$> o .: "grant_type"
|
fromForm f = ClientData
|
||||||
<*> (o .: ps PassCreds --TODO add alternatives
|
<$> parseUnique "grant_type" f
|
||||||
<|> o .: ps AuthCode
|
<*> (parseUnique @String (ps PassCreds) f --TODO add alternatives
|
||||||
<|> o .: ps Implicit
|
>> parseUnique @String (ps AuthCode) f
|
||||||
<|> o .: ps ClientCreds)
|
>> parseUnique @String (ps Implicit) f
|
||||||
<*> o .:? "username"
|
>> parseUnique @String (ps ClientCreds) f)
|
||||||
<*> o .: "client_id"
|
<*> parseMaybe "username" f
|
||||||
<*> o .: "client_secret"
|
<*> parseMaybe "client_id" f
|
||||||
<*> o .:? "redirect_uri"
|
<*> parseMaybe "client_secret" f
|
||||||
where ps = fromString @Key . show
|
<*> parseMaybe "redirect_uri" f
|
||||||
|
where ps = pack . show
|
||||||
|
|
||||||
data GrantType = PassCreds | AuthCode | Implicit | ClientCreds deriving (Eq)
|
data GrantType = PassCreds | AuthCode | Implicit | ClientCreds deriving (Eq)
|
||||||
|
|
||||||
@ -174,10 +177,10 @@ instance Show GrantType where
|
|||||||
show AuthCode = "code"
|
show AuthCode = "code"
|
||||||
show _ = undefined --TODO support other flows
|
show _ = undefined --TODO support other flows
|
||||||
|
|
||||||
instance FromJSON GrantType where
|
instance FromHttpApiData GrantType where
|
||||||
parseJSON (String s)
|
parseQueryParam s
|
||||||
| s == pack (show AuthCode) = pure AuthCode
|
| s == pack (show AuthCode) = Right AuthCode
|
||||||
| otherwise = error $ show s ++ " grant type not supported yet"
|
| otherwise = Left $ s <> " grant type not supported yet"
|
||||||
|
|
||||||
data JWT = JWT
|
data JWT = JWT
|
||||||
{ issuer :: Text
|
{ issuer :: Text
|
||||||
@ -206,7 +209,7 @@ instance FromHttpApiData JWTWrapper where
|
|||||||
Nothing -> Left "Invalid JWT wrapper"
|
Nothing -> Left "Invalid JWT wrapper"
|
||||||
|
|
||||||
type Token = "token"
|
type Token = "token"
|
||||||
:> ReqBody '[JSON] ClientData
|
:> ReqBody '[FormUrlEncoded] ClientData
|
||||||
:> Post '[JSON] JWTWrapper
|
:> Post '[JSON] JWTWrapper
|
||||||
|
|
||||||
tokenEndpoint :: AuthServer Token
|
tokenEndpoint :: AuthServer Token
|
||||||
@ -215,9 +218,10 @@ tokenEndpoint = provideToken
|
|||||||
provideToken :: ClientData -> AuthHandler JWTWrapper
|
provideToken :: ClientData -> AuthHandler JWTWrapper
|
||||||
provideToken client = case (grantType client) of
|
provideToken client = case (grantType client) of
|
||||||
AuthCode -> do
|
AuthCode -> do
|
||||||
unless (Client (pack $ clientID client) (pack $ clientSecret client) `elem` trustedClients) .
|
unless (isNothing (clientID client >> clientSecret client)
|
||||||
throwError $ err500 { errBody = "Invalid client" }
|
|| Client (pack . fromJust $ clientID client) (pack . fromJust $ clientSecret client) `elem` trustedClients) .
|
||||||
valid <- asks (verify (pack $ grant client) (clientID client)) >>= liftIO
|
throwError $ err500 { errBody = "Invalid client" }
|
||||||
|
valid <- asks (verify (pack $ grant client) (clientID client)) >>= liftIO -- TODO verify redirect url here
|
||||||
unless valid . throwError $ err500 { errBody = "Invalid authorisation code" }
|
unless valid . 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
|
token <- asks mkToken >>= liftIO
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user