Skip to content

Commit

Permalink
refactor: remove caching empty JWT in Auth header
Browse files Browse the repository at this point in the history
  • Loading branch information
taimoorzaeem committed Feb 28, 2025
1 parent c9a625c commit 6cf7bc3
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 6 deletions.
16 changes: 10 additions & 6 deletions src/PostgREST/Auth.hs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ import Protolude

-- | Receives the JWT secret and audience (from config) and a JWT and returns a
-- JSON object of JWT claims.
parseToken :: AppConfig -> ByteString -> UTCTime -> ExceptT Error IO JSON.Value
parseToken _ "" _ = return JSON.emptyObject
parseToken AppConfig{..} token time = do
parseToken :: AppConfig -> Maybe ByteString -> UTCTime -> ExceptT Error IO JSON.Value
parseToken _ Nothing _ = return JSON.emptyObject
parseToken AppConfig{..} (Just token) time = do
secret <- liftEither . maybeToRight JwtTokenMissing $ configJWKS
eitherContent <- liftIO $ JWT.decode (JWT.keys secret) Nothing token
content <- liftEither . mapLeft jwtDecodeError $ eitherContent
Expand Down Expand Up @@ -148,7 +148,7 @@ middleware appState app req respond = do
conf <- getConfig appState
time <- getTime appState

let token = fromMaybe "" $ Wai.extractBearerAuth =<< lookup HTTP.hAuthorization (Wai.requestHeaders req)
let token = Wai.extractBearerAuth =<< lookup HTTP.hAuthorization (Wai.requestHeaders req)
parseJwt = runExceptT $ parseToken conf token time >>= parseClaims conf
jwtCacheState = getJwtCacheState appState

Expand All @@ -160,15 +160,19 @@ middleware appState app req respond = do
return $ req { Wai.vault = Wai.vault req & Vault.insert authResultKey authResult & Vault.insert jwtDurKey dur }

(True, maxLifetime) -> do
(dur, authResult) <- timeItT $ lookupJwtCache jwtCacheState token maxLifetime parseJwt time
(dur, authResult) <- timeItT $ case token of
Nothing -> parseJwt

Check warning on line 164 in src/PostgREST/Auth.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/Auth.hs#L164

Added line #L164 was not covered by tests
Just tok -> lookupJwtCache jwtCacheState tok maxLifetime parseJwt time
return $ req { Wai.vault = Wai.vault req & Vault.insert authResultKey authResult & Vault.insert jwtDurKey dur }

(False, 0) -> do
authResult <- parseJwt
return $ req { Wai.vault = Wai.vault req & Vault.insert authResultKey authResult }

(False, maxLifetime) -> do
authResult <- lookupJwtCache jwtCacheState token maxLifetime parseJwt time
authResult <- case token of
Nothing -> parseJwt

Check warning on line 174 in src/PostgREST/Auth.hs

View check run for this annotation

Codecov / codecov/patch

src/PostgREST/Auth.hs#L174

Added line #L174 was not covered by tests
Just tok -> lookupJwtCache jwtCacheState tok maxLifetime parseJwt time
return $ req { Wai.vault = Wai.vault req & Vault.insert authResultKey authResult }

app req' respond
Expand Down
11 changes: 11 additions & 0 deletions test/spec/Feature/Auth/AuthSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,14 @@ spec = describe "authorization" $ do
`shouldRespondWith` 200
request methodGet "/authors_only" [authHeader "bearer" token] ""
`shouldRespondWith` 200

describe "when JWT is empty string" $ do

it "raises error on empty token in Auth header" $ do
let auth = authHeaderJWT ""
request methodGet "/authors_only"
[auth]
""
`shouldRespondWith`
[json| {"code":"PGRST301","details":null,"hint":null,"message":"JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 2)"} |]
{ matchStatus = 401 }

0 comments on commit 6cf7bc3

Please sign in to comment.