@@ -37,12 +37,13 @@ import PostgREST.Auth.Types (AuthResult (..))
3737import PostgREST.Config (AppConfig (.. ), FilterExp (.. ), JSPath ,
3838 JSPathExp (.. ), audMatchesCfg )
3939import PostgREST.Error (Error (.. ),
40- JwtClaimsError (AudClaimNotStringOrArray , ExpClaimNotNumber , IatClaimNotNumber , JWTExpired , JWTIssuedAtFuture , JWTNotInAudience , JWTNotYetValid , NbfClaimNotNumber , ParsingClaimsFailed ),
40+ JwtClaimsError (AudClaimNotStringOrURIOrArray , ExpClaimNotNumber , IatClaimNotNumber , JWTExpired , JWTIssuedAtFuture , JWTNotInAudience , JWTNotYetValid , NbfClaimNotNumber , ParsingClaimsFailed ),
4141 JwtDecodeError (.. ), JwtError (.. ))
4242
4343import Data.Aeson ((.:?) )
4444import Data.Aeson.Types (parseMaybe )
4545import Jose.Jwk (JwkSet )
46+ import Network.URI (isURI )
4647import Protolude hiding (first )
4748
4849parseAndDecodeClaims :: (MonadError Error m , MonadIO m ) => JwkSet -> ByteString -> m JSON. Object
@@ -55,7 +56,13 @@ decodeClaims _ = throwError $ JwtErr $ JwtDecodeErr UnsupportedTokenType
5556validateClaims :: MonadError Error m => UTCTime -> (Text -> Bool ) -> JSON. Object -> m ()
5657validateClaims time audMatches claims = liftEither $ maybeToLeft () (fmap JwtErr . getAlt $ JwtClaimsErr <$> checkForErrors time audMatches claims)
5758
58- data ValidAud = VAString Text | VAArray [Text ] deriving Generic
59+ newtype StringOrURI = StringOrURI { unStringOrURI :: Text }
60+ instance JSON. FromJSON StringOrURI where
61+ parseJSON = fmap StringOrURI . mfilter isValidURI . JSON. parseJSON
62+ where
63+ isValidURI = (||) <$> not . T. isInfixOf " :" <*> isURI . T. unpack
64+
65+ data ValidAud = VAString StringOrURI | VAArray [StringOrURI ] deriving Generic
5966instance JSON. FromJSON ValidAud where
6067 parseJSON = JSON. genericParseJSON JSON. defaultOptions { JSON. sumEncoding = JSON. UntaggedValue }
6168
@@ -65,7 +72,7 @@ checkForErrors time audMatches = mconcat
6572 claim " exp" ExpClaimNotNumber $ inThePast JWTExpired
6673 , claim " nbf" NbfClaimNotNumber $ inTheFuture JWTNotYetValid
6774 , claim " iat" IatClaimNotNumber $ inTheFuture JWTIssuedAtFuture
68- , claim " aud" AudClaimNotStringOrArray $ checkValue (not . validAud) JWTNotInAudience
75+ , claim " aud" AudClaimNotStringOrURIOrArray $ checkValue (not . validAud) JWTNotInAudience
6976 ]
7077 where
7178 allowedSkewSeconds = 30 :: Int64
@@ -79,8 +86,9 @@ checkForErrors time audMatches = mconcat
7986 checkTime cond = checkValue (cond. sciToInt)
8087
8188 validAud = \ case
82- (VAString aud) -> audMatches aud
83- (VAArray auds) -> null auds || any audMatches auds
89+ (VAString aud) -> validAudString aud
90+ (VAArray auds) -> null auds || any validAudString auds
91+ validAudString = audMatches . unStringOrURI
8492
8593 checkValue invalid msg val =
8694 if invalid val then
0 commit comments