Treat JWT as a Secret, not String
This commit is contained in:
@@ -184,7 +184,7 @@ app dbStructure conf reqBody req =
|
|||||||
hasPrefer val = any (\(h,v) -> h == "Prefer" && v == val) hdrs
|
hasPrefer val = any (\(h,v) -> h == "Prefer" && v == val) hdrs
|
||||||
accept = lookupHeader hAccept
|
accept = lookupHeader hAccept
|
||||||
schema = cs $ configSchema conf
|
schema = cs $ configSchema conf
|
||||||
jwtSecret = (cs $ configJwtSecret conf) :: Text
|
jwtSecret = configJwtSecret conf
|
||||||
range = rangeRequested hdrs
|
range = rangeRequested hdrs
|
||||||
allOrigins = ("Access-Control-Allow-Origin", "*") :: Header
|
allOrigins = ("Access-Control-Allow-Origin", "*") :: Header
|
||||||
contentType = fromMaybe "application/json" $ contentTypeForAccept accept
|
contentType = fromMaybe "application/json" $ contentTypeForAccept accept
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ claimsToSQL = map setVar . toList
|
|||||||
returns a map of JWT claims
|
returns a map of JWT claims
|
||||||
In case there is any problem decoding the JWT it returns Nothing.
|
In case there is any problem decoding the JWT it returns Nothing.
|
||||||
-}
|
-}
|
||||||
jwtClaims :: Text -> Text -> NominalDiffTime -> Maybe JWT.ClaimsMap
|
jwtClaims :: JWT.Secret -> Text -> NominalDiffTime -> Maybe JWT.ClaimsMap
|
||||||
jwtClaims secret input time =
|
jwtClaims secret input time =
|
||||||
case join $ claim JWT.exp of
|
case join $ claim JWT.exp of
|
||||||
Just expires ->
|
Just expires ->
|
||||||
@@ -60,7 +60,7 @@ jwtClaims secret input time =
|
|||||||
else Nothing
|
else Nothing
|
||||||
_ -> customClaims
|
_ -> customClaims
|
||||||
where
|
where
|
||||||
decoded = JWT.decodeAndVerifySignature (JWT.secret secret) input
|
decoded = JWT.decodeAndVerifySignature secret input
|
||||||
claim :: (JWT.JWTClaimsSet -> a) -> Maybe a
|
claim :: (JWT.JWTClaimsSet -> a) -> Maybe a
|
||||||
claim prop = prop . JWT.claims <$> decoded
|
claim prop = prop . JWT.claims <$> decoded
|
||||||
customClaims = claim JWT.unregisteredClaims
|
customClaims = claim JWT.unregisteredClaims
|
||||||
@@ -74,8 +74,8 @@ setRole role = "set local role " <> cs (pgFmtLit role) <> ";"
|
|||||||
Receives the JWT secret (from config) and a JWT and a JSON value
|
Receives the JWT secret (from config) and a JWT and a JSON value
|
||||||
and returns a signed JWT.
|
and returns a signed JWT.
|
||||||
-}
|
-}
|
||||||
tokenJWT :: Text -> Value -> Text
|
tokenJWT :: JWT.Secret -> Value -> Text
|
||||||
tokenJWT secret (Array a) = JWT.encodeSigned JWT.HS256 (JWT.secret secret)
|
tokenJWT secret (Array a) = JWT.encodeSigned JWT.HS256 secret
|
||||||
JWT.def { JWT.unregisteredClaims = fromHashMap o }
|
JWT.def { JWT.unregisteredClaims = fromHashMap o }
|
||||||
where
|
where
|
||||||
Object o = if V.null a then emptyObject else V.head a
|
Object o = if V.null a then emptyObject else V.head a
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import Network.Wai
|
|||||||
import Network.Wai.Middleware.Cors (CorsResourcePolicy (..))
|
import Network.Wai.Middleware.Cors (CorsResourcePolicy (..))
|
||||||
import Options.Applicative
|
import Options.Applicative
|
||||||
import Paths_postgrest (version)
|
import Paths_postgrest (version)
|
||||||
|
import Web.JWT (Secret, secret)
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
-- | Data type to store all command line options
|
-- | Data type to store all command line options
|
||||||
@@ -38,7 +39,7 @@ data AppConfig = AppConfig {
|
|||||||
, configPort :: Int
|
, configPort :: Int
|
||||||
, configAnonRole :: String
|
, configAnonRole :: String
|
||||||
, configSchema :: String
|
, configSchema :: String
|
||||||
, configJwtSecret :: String
|
, configJwtSecret :: Secret
|
||||||
, configPool :: Int
|
, configPool :: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +50,8 @@ argParser = AppConfig
|
|||||||
<*> option auto (long "port" <> short 'p' <> help "port number on which to run HTTP server" <> metavar "PORT" <> value 3000 <> showDefault)
|
<*> option auto (long "port" <> short 'p' <> help "port number on which to run HTTP server" <> metavar "PORT" <> value 3000 <> showDefault)
|
||||||
<*> strOption (long "anonymous" <> short 'a' <> help "postgres role to use for non-authenticated requests" <> metavar "ROLE")
|
<*> strOption (long "anonymous" <> short 'a' <> help "postgres role to use for non-authenticated requests" <> metavar "ROLE")
|
||||||
<*> strOption (long "schema" <> short 's' <> help "schema to use for API routes" <> metavar "NAME" <> value "1" <> showDefault)
|
<*> strOption (long "schema" <> short 's' <> help "schema to use for API routes" <> metavar "NAME" <> value "1" <> showDefault)
|
||||||
<*> strOption (long "jwt-secret" <> short 'j' <> help "secret used to encrypt and decrypt JWT tokens" <> metavar "SECRET" <> value "secret" <> showDefault)
|
<*> (secret . cs <$>
|
||||||
|
strOption (long "jwt-secret" <> short 'j' <> help "secret used to encrypt and decrypt JWT tokens" <> metavar "SECRET" <> value "secret" <> showDefault))
|
||||||
<*> option auto (long "pool" <> short 'o' <> help "max connections in database pool" <> metavar "COUNT" <> value 10 <> showDefault)
|
<*> option auto (long "pool" <> short 'o' <> help "max connections in database pool" <> metavar "COUNT" <> value 10 <> showDefault)
|
||||||
|
|
||||||
defaultCorsPolicy :: CorsResourcePolicy
|
defaultCorsPolicy :: CorsResourcePolicy
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import Network.Wai.Middleware.RequestLogger (logStdout)
|
|||||||
import System.IO (BufferMode (..),
|
import System.IO (BufferMode (..),
|
||||||
hSetBuffering, stderr,
|
hSetBuffering, stderr,
|
||||||
stdin, stdout)
|
stdin, stdout)
|
||||||
|
import Web.JWT (secret)
|
||||||
|
|
||||||
isServerVersionSupported :: H.Session P.Postgres IO Bool
|
isServerVersionSupported :: H.Session P.Postgres IO Bool
|
||||||
isServerVersionSupported = do
|
isServerVersionSupported = do
|
||||||
@@ -43,7 +44,7 @@ main = do
|
|||||||
conf <- readOptions
|
conf <- readOptions
|
||||||
let port = configPort conf
|
let port = configPort conf
|
||||||
|
|
||||||
unless ("secret" /= configJwtSecret conf) $
|
unless (secret "secret" /= configJwtSecret conf) $
|
||||||
putStrLn "WARNING, running in insecure mode, JWT secret is the default value"
|
putStrLn "WARNING, running in insecure mode, JWT secret is the default value"
|
||||||
Prelude.putStrLn $ "Listening on port " ++
|
Prelude.putStrLn $ "Listening on port " ++
|
||||||
(show $ configPort conf :: String)
|
(show $ configPort conf :: String)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ runWithClaims conf app req = do
|
|||||||
where
|
where
|
||||||
stmt c = B.Stmt c V.empty True
|
stmt c = B.Stmt c V.empty True
|
||||||
hdrs = requestHeaders req
|
hdrs = requestHeaders req
|
||||||
jwtSecret = (cs $ configJwtSecret conf) :: Text
|
jwtSecret = configJwtSecret conf
|
||||||
auth = fromMaybe "" $ lookup hAuthorization hdrs
|
auth = fromMaybe "" $ lookup hAuthorization hdrs
|
||||||
anon = cs $ configAnonRole conf
|
anon = cs $ configAnonRole conf
|
||||||
setAnon = setRole anon
|
setAnon = setRole anon
|
||||||
|
|||||||
Reference in New Issue
Block a user