Ensure JWT expires

This commit is contained in:
calebmer
2015-11-05 17:04:54 -05:00
parent 4803d7c828
commit aab2f0d1f1
7 changed files with 68 additions and 34 deletions
+12 -2
View File
@@ -25,6 +25,7 @@ import Data.Map as M (fromList, toList)
import Data.Monoid ((<>))
import Data.String.Conversions (cs)
import Data.Text (Text)
import Data.Time.Clock (NominalDiffTime)
import PostgREST.PgQuery (pgFmtLit, pgFmtIdent, unquoted)
import qualified Web.JWT as JWT
import qualified Data.HashMap.Lazy as H
@@ -49,10 +50,19 @@ claimsToSQL = map setVar . toList
returns a map of JWT claims
In case there is any problem decoding the JWT it returns Nothing.
-}
jwtClaims :: Text -> Text -> Maybe JWT.ClaimsMap
jwtClaims secret input = JWT.unregisteredClaims . JWT.claims <$> decoded
jwtClaims :: Text -> Text -> NominalDiffTime -> Maybe JWT.ClaimsMap
jwtClaims secret input time =
case claim JWT.exp of
Just (Just expires) ->
if JWT.secondsSinceEpoch expires > time
then customClaims
else Nothing
_ -> customClaims
where
decoded = JWT.decodeAndVerifySignature (JWT.secret secret) input
claim :: (JWT.JWTClaimsSet -> a) -> Maybe a
claim prop = prop . JWT.claims <$> decoded
customClaims = claim JWT.unregisteredClaims
-- | Receives the name of a role and returns a SET ROLE statement
setRole :: Text -> Text
+3 -8
View File
@@ -24,6 +24,7 @@ import qualified Hasql.Postgres as P
import Network.Wai
import Network.Wai.Handler.Warp hiding (Connection)
import Network.Wai.Middleware.RequestLogger (logStdout)
import Data.Time.Clock.POSIX (getPOSIXTime)
import System.IO (BufferMode (..),
hSetBuffering, stderr,
stdin, stdout)
@@ -72,13 +73,6 @@ main = do
<> show minimumPgVersion)
) supportedOrError
-- what was this code for?
-- roleOrError <- H.session pool $ do
-- Identity (role :: Text) <- H.tx Nothing $ H.singleEx
-- [H.stmt|SELECT SESSION_USER|]
-- return role
-- authenticator <- either hasqlError return roleOrError
let txSettings = Just (H.ReadCommitted, Just True)
metadata <- H.session pool $ H.tx txSettings $ do
tabs <- allTables
@@ -105,7 +99,8 @@ main = do
-- print $ findRelation (fakeRels ++ allRels) "test" "pg_source" "clients"
runSettings appSettings $ middle $ \ req respond -> do
time <- getPOSIXTime
body <- strictRequestBody req
resOrError <- liftIO $ H.session pool $ H.tx txSettings $
runWithClaims conf (app dbstructure conf body) req
runWithClaims conf time (app dbstructure conf body) req
either (respond . errResponse) respond resOrError
+23 -19
View File
@@ -7,6 +7,7 @@ import Data.Maybe (fromMaybe, isNothing)
import Data.Monoid
import Data.Text
import Data.String.Conversions (cs)
import Data.Time.Clock (NominalDiffTime)
import qualified Hasql as H
import qualified Hasql.Postgres as P
@@ -32,27 +33,30 @@ import qualified Data.Vector as V
import qualified Hasql.Backend as B
import qualified Data.Map.Lazy as M
runWithClaims :: forall s. AppConfig ->
runWithClaims :: forall s. AppConfig -> NominalDiffTime ->
(Request -> H.Tx P.Postgres s Response) ->
Request -> H.Tx P.Postgres s Response
runWithClaims conf app req = do
mapM_ H.unitEx $ stmt <$> env
app req
where
stmt = (flip $ flip B.Stmt V.empty) True
hdrs = requestHeaders req
jwtSecret = (cs $ configJwtSecret conf) :: Text
auth = fromMaybe "" $ lookup hAuthorization hdrs
anon = cs $ configAnonRole conf
claims =
fromMaybe (M.fromList []) $
case split (==' ') (cs auth) of
("Bearer" : jwt : _) -> jwtClaims jwtSecret jwt
_ -> Nothing
env = if M.member "role" claims
then jwtEnv
else setRole anon : jwtEnv
jwtEnv = claimsToSQL claims
runWithClaims conf time app req = do
_ <- H.unitEx $ stmt setAnon
case split (== ' ') (cs auth) of
("Bearer" : tokenStr : _) ->
case jwtClaims jwtSecret tokenStr time of
Just claims ->
if M.member "role" claims
then do
mapM_ H.unitEx $ stmt <$> claimsToSQL claims
app req
else invalidJWT
_ -> invalidJWT
_ -> app req
where
stmt = (flip $ flip B.Stmt V.empty) True
hdrs = requestHeaders req
jwtSecret = (cs $ configJwtSecret conf) :: Text
auth = fromMaybe "" $ lookup hAuthorization hdrs
anon = cs $ configAnonRole conf
setAnon = setRole anon
invalidJWT = return $ responseLBS status400 [] "Invalid JWT"
redirectInsecure :: Application -> Application
redirectInsecure app req respond = do