refactor: group jwt errors
This commit is contained in:
committed by
Steve Chavez
parent
c9a625ced6
commit
4ddf33df76
@@ -48,7 +48,7 @@ import PostgREST.Auth.JwtCache (lookupJwtCache)
|
|||||||
import PostgREST.Auth.Types (AuthResult (..))
|
import PostgREST.Auth.Types (AuthResult (..))
|
||||||
import PostgREST.Config (AppConfig (..), FilterExp (..),
|
import PostgREST.Config (AppConfig (..), FilterExp (..),
|
||||||
JSPath, JSPathExp (..))
|
JSPath, JSPathExp (..))
|
||||||
import PostgREST.Error (Error (..))
|
import PostgREST.Error (Error (..), JwtError (..))
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
@@ -57,20 +57,20 @@ import Protolude
|
|||||||
parseToken :: AppConfig -> ByteString -> UTCTime -> ExceptT Error IO JSON.Value
|
parseToken :: AppConfig -> ByteString -> UTCTime -> ExceptT Error IO JSON.Value
|
||||||
parseToken _ "" _ = return JSON.emptyObject
|
parseToken _ "" _ = return JSON.emptyObject
|
||||||
parseToken AppConfig{..} token time = do
|
parseToken AppConfig{..} token time = do
|
||||||
secret <- liftEither . maybeToRight JwtTokenMissing $ configJWKS
|
secret <- liftEither . maybeToRight (JwtErr JwtTokenMissing) $ configJWKS
|
||||||
eitherContent <- liftIO $ JWT.decode (JWT.keys secret) Nothing token
|
eitherContent <- liftIO $ JWT.decode (JWT.keys secret) Nothing token
|
||||||
content <- liftEither . mapLeft jwtDecodeError $ eitherContent
|
content <- liftEither . mapLeft (JwtErr . jwtDecodeError) $ eitherContent
|
||||||
liftEither $ verifyClaims content
|
liftEither $ mapLeft JwtErr $ verifyClaims content
|
||||||
where
|
where
|
||||||
-- TODO: Improve errors, those were just taken as-is from hs-jose to avoid
|
-- TODO: Improve errors, those were just taken as-is from hs-jose to avoid
|
||||||
-- breaking changes.
|
-- breaking changes.
|
||||||
jwtDecodeError :: JWT.JwtError -> Error
|
jwtDecodeError :: JWT.JwtError -> JwtError
|
||||||
jwtDecodeError (JWT.KeyError _) = JwtTokenInvalid "JWSError JWSInvalidSignature"
|
jwtDecodeError (JWT.KeyError _) = JwtTokenInvalid "JWSError JWSInvalidSignature"
|
||||||
jwtDecodeError JWT.BadCrypto = JwtTokenInvalid "JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 2)"
|
jwtDecodeError JWT.BadCrypto = JwtTokenInvalid "JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 2)"
|
||||||
jwtDecodeError (JWT.BadAlgorithm _) = JwtTokenInvalid "JWSError JWSNoSignatures"
|
jwtDecodeError (JWT.BadAlgorithm _) = JwtTokenInvalid "JWSError JWSNoSignatures"
|
||||||
jwtDecodeError e = JwtTokenInvalid $ show e
|
jwtDecodeError e = JwtTokenInvalid $ show e
|
||||||
|
|
||||||
verifyClaims :: JWT.JwtContent -> Either Error JSON.Value
|
verifyClaims :: JWT.JwtContent -> Either JwtError JSON.Value
|
||||||
verifyClaims (JWT.Jws (_, claims)) = case JSON.decodeStrict claims of
|
verifyClaims (JWT.Jws (_, claims)) = case JSON.decodeStrict claims of
|
||||||
Nothing -> Left $ JwtTokenInvalid "Parsing claims failed"
|
Nothing -> Left $ JwtTokenInvalid "Parsing claims failed"
|
||||||
Just (JSON.Object mclaims)
|
Just (JSON.Object mclaims)
|
||||||
@@ -110,7 +110,7 @@ parseClaims :: Monad m =>
|
|||||||
AppConfig -> JSON.Value -> ExceptT Error m AuthResult
|
AppConfig -> JSON.Value -> ExceptT Error m AuthResult
|
||||||
parseClaims AppConfig{..} jclaims@(JSON.Object mclaims) = do
|
parseClaims AppConfig{..} jclaims@(JSON.Object mclaims) = do
|
||||||
-- role defaults to anon if not specified in jwt
|
-- role defaults to anon if not specified in jwt
|
||||||
role <- liftEither . maybeToRight JwtTokenRequired $
|
role <- liftEither . maybeToRight (JwtErr JwtTokenRequired) $
|
||||||
unquoted <$> walkJSPath (Just jclaims) configJwtRoleClaimKey <|> configDbAnonRole
|
unquoted <$> walkJSPath (Just jclaims) configJwtRoleClaimKey <|> configDbAnonRole
|
||||||
return AuthResult
|
return AuthResult
|
||||||
{ authClaims = mclaims & KM.insert "role" (JSON.toJSON $ decodeUtf8 role)
|
{ authClaims = mclaims & KM.insert "role" (JSON.toJSON $ decodeUtf8 role)
|
||||||
|
|||||||
+24
-10
@@ -12,6 +12,7 @@ module PostgREST.Error
|
|||||||
, RangeError(..)
|
, RangeError(..)
|
||||||
, PgError(..)
|
, PgError(..)
|
||||||
, Error(..)
|
, Error(..)
|
||||||
|
, JwtError (..)
|
||||||
, errorPayload
|
, errorPayload
|
||||||
, status
|
, status
|
||||||
) where
|
) where
|
||||||
@@ -567,32 +568,47 @@ pgErrorStatus authed (SQL.SessionUsageError (SQL.QueryError _ _ (SQL.ResultError
|
|||||||
_ -> HTTP.status500
|
_ -> HTTP.status500
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: separate "SchemaCacheError" from ApiRequestError similar to how we
|
||||||
|
-- group them in docs
|
||||||
data Error
|
data Error
|
||||||
= ApiRequestError ApiRequestError
|
= ApiRequestError ApiRequestError
|
||||||
| JwtTokenInvalid Text
|
| JwtErr JwtError
|
||||||
| JwtTokenMissing
|
|
||||||
| JwtTokenRequired
|
|
||||||
| NoSchemaCacheError
|
| NoSchemaCacheError
|
||||||
| PgErr PgError
|
| PgErr PgError
|
||||||
|
|
||||||
|
data JwtError
|
||||||
|
= JwtTokenInvalid Text
|
||||||
|
| JwtTokenMissing
|
||||||
|
| JwtTokenRequired
|
||||||
|
|
||||||
instance PgrstError Error where
|
instance PgrstError Error where
|
||||||
status (ApiRequestError err) = status err
|
status (ApiRequestError err) = status err
|
||||||
status JwtTokenInvalid{} = HTTP.unauthorized401
|
status (JwtErr err) = status err
|
||||||
status JwtTokenMissing = HTTP.status500
|
|
||||||
status JwtTokenRequired = HTTP.unauthorized401
|
|
||||||
status NoSchemaCacheError = HTTP.status503
|
status NoSchemaCacheError = HTTP.status503
|
||||||
status (PgErr err) = status err
|
status (PgErr err) = status err
|
||||||
|
|
||||||
headers (ApiRequestError err) = headers err
|
headers (ApiRequestError err) = headers err
|
||||||
headers (JwtTokenInvalid m) = [invalidTokenHeader m]
|
headers (JwtErr err) = headers err
|
||||||
headers JwtTokenRequired = [requiredTokenHeader]
|
|
||||||
headers (PgErr err) = headers err
|
headers (PgErr err) = headers err
|
||||||
headers _ = mempty
|
headers _ = mempty
|
||||||
|
|
||||||
|
instance PgrstError JwtError where
|
||||||
|
status JwtTokenInvalid{} = HTTP.unauthorized401
|
||||||
|
status JwtTokenMissing = HTTP.status500
|
||||||
|
status JwtTokenRequired = HTTP.unauthorized401
|
||||||
|
|
||||||
|
headers (JwtTokenInvalid m) = [invalidTokenHeader m]
|
||||||
|
headers JwtTokenRequired = [requiredTokenHeader]
|
||||||
|
headers _ = mempty
|
||||||
|
|
||||||
instance JSON.ToJSON Error where
|
instance JSON.ToJSON Error where
|
||||||
|
toJSON (ApiRequestError err) = JSON.toJSON err
|
||||||
|
toJSON (JwtErr err) = JSON.toJSON err
|
||||||
|
toJSON (PgErr err) = JSON.toJSON err
|
||||||
toJSON NoSchemaCacheError = toJsonPgrstError
|
toJSON NoSchemaCacheError = toJsonPgrstError
|
||||||
ConnectionErrorCode02 "Could not query the database for the schema cache. Retrying." Nothing Nothing
|
ConnectionErrorCode02 "Could not query the database for the schema cache. Retrying." Nothing Nothing
|
||||||
|
|
||||||
|
instance JSON.ToJSON JwtError where
|
||||||
toJSON JwtTokenMissing = toJsonPgrstError
|
toJSON JwtTokenMissing = toJsonPgrstError
|
||||||
JWTErrorCode00 "Server lacks JWT secret" Nothing Nothing
|
JWTErrorCode00 "Server lacks JWT secret" Nothing Nothing
|
||||||
|
|
||||||
@@ -602,8 +618,6 @@ instance JSON.ToJSON Error where
|
|||||||
toJSON JwtTokenRequired = toJsonPgrstError
|
toJSON JwtTokenRequired = toJsonPgrstError
|
||||||
JWTErrorCode02 "Anonymous access is disabled" Nothing Nothing
|
JWTErrorCode02 "Anonymous access is disabled" Nothing Nothing
|
||||||
|
|
||||||
toJSON (PgErr err) = JSON.toJSON err
|
|
||||||
toJSON (ApiRequestError err) = JSON.toJSON err
|
|
||||||
|
|
||||||
invalidTokenHeader :: Text -> Header
|
invalidTokenHeader :: Text -> Header
|
||||||
invalidTokenHeader m =
|
invalidTokenHeader m =
|
||||||
|
|||||||
Reference in New Issue
Block a user