Require JWT secret, remove default, optionally read from file

Fixes #474, fixes #495 when file is used
This commit is contained in:
Joe Nelson
2016-09-24 21:28:08 -07:00
parent 7bf5b0106d
commit 449480bf01
4 changed files with 21 additions and 17 deletions
+10 -4
View File
@@ -12,6 +12,7 @@ import PostgREST.OpenAPI (isMalformedProxyUri)
import PostgREST.DbStructure import PostgREST.DbStructure
import Data.String (IsString (..)) import Data.String (IsString (..))
import Data.Text (stripPrefix)
import Data.Function (id) import Data.Function (id)
import qualified Hasql.Query as H import qualified Hasql.Query as H
import qualified Hasql.Session as H import qualified Hasql.Session as H
@@ -21,7 +22,6 @@ import qualified Hasql.Pool as P
import Network.Wai.Handler.Warp import Network.Wai.Handler.Warp
import System.IO (BufferMode (..), import System.IO (BufferMode (..),
hSetBuffering) hSetBuffering)
import Web.JWT (secret)
import Data.IORef import Data.IORef
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
import System.Posix.Signals import System.Posix.Signals
@@ -42,7 +42,7 @@ main = do
hSetBuffering stdin LineBuffering hSetBuffering stdin LineBuffering
hSetBuffering stderr NoBuffering hSetBuffering stderr NoBuffering
conf <- readOptions conf <- loadSecretFile =<< readOptions
let host = configHost conf let host = configHost conf
port = configPort conf port = configPort conf
proxy = configProxyUri conf proxy = configProxyUri conf
@@ -55,8 +55,6 @@ main = do
when (isMalformedProxyUri $ toS <$> proxy) $ panic when (isMalformedProxyUri $ toS <$> proxy) $ panic
"Malformed proxy uri, a correct example: https://example.com:8443/basePath" "Malformed proxy uri, a correct example: https://example.com:8443/basePath"
unless (secret "secret" /= configJwtSecret conf) $
putStrLn ("WARNING, running in insecure mode, JWT secret is the default value" :: Text)
putStrLn $ ("Listening on port " :: Text) <> show (configPort conf) putStrLn $ ("Listening on port " :: Text) <> show (configPort conf)
pool <- P.acquire (configPool conf, 10, pgSettings) pool <- P.acquire (configPool conf, 10, pgSettings)
@@ -86,3 +84,11 @@ main = do
#endif #endif
runSettings appSettings $ postgrest conf refDbStructure pool runSettings appSettings $ postgrest conf refDbStructure pool
loadSecretFile :: AppConfig -> IO AppConfig
loadSecretFile conf = do
let s = configJwtSecret conf
real <- case stripPrefix "@" s of
Nothing -> return s -- the string is the secret, not a filename
Just filename -> readFile (toS filename)
return conf { configJwtSecret = real }
+5 -4
View File
@@ -25,12 +25,13 @@ import qualified Text.InterpolatedString.Perl6 as P6 (q)
import Network.HTTP.Types.Header import Network.HTTP.Types.Header
import Network.HTTP.Types.Status import Network.HTTP.Types.Status
import Network.HTTP.Types.URI (renderSimpleQuery) import Network.HTTP.Types.URI (renderSimpleQuery)
import Network.Wai import Network.Wai
import Network.Wai.Middleware.RequestLogger (logStdout) import Network.Wai.Middleware.RequestLogger (logStdout)
import Web.JWT (secret)
import Data.Aeson import Data.Aeson
import Data.Aeson.Types (emptyArray) import Data.Aeson.Types (emptyArray)
import Data.Time.Clock.POSIX (getPOSIXTime) import Data.Time.Clock.POSIX (getPOSIXTime)
import qualified Data.Vector as V import qualified Data.Vector as V
import qualified Hasql.Transaction as H import qualified Hasql.Transaction as H
@@ -79,7 +80,7 @@ postgrest conf refDbStructure pool =
let schema = toS $ configSchema conf let schema = toS $ configSchema conf
apiRequest = userApiRequest schema req body apiRequest = userApiRequest schema req body
eClaims = jwtClaims (configJwtSecret conf) (iJWT apiRequest) time eClaims = jwtClaims (secret $ configJwtSecret conf) (iJWT apiRequest) time
authed = containsRole eClaims authed = containsRole eClaims
handleReq = runWithClaims conf eClaims (app dbStructure conf) apiRequest handleReq = runWithClaims conf eClaims (app dbStructure conf) apiRequest
txMode = transactionMode $ iAction apiRequest txMode = transactionMode $ iAction apiRequest
@@ -211,7 +212,7 @@ app dbStructure conf apiRequest =
Just (PayloadJSON (UniformObjects payload))) -> do Just (PayloadJSON (UniformObjects payload))) -> do
let p = V.head payload let p = V.head payload
singular = iPreferSingular apiRequest singular = iPreferSingular apiRequest
jwtSecret = configJwtSecret conf jwtSecret = secret $ configJwtSecret conf
returnType = lookup (qiName qi) $ dbProcs dbStructure returnType = lookup (qiName qi) $ dbProcs dbStructure
returnsJWT = fromMaybe False $ returnsJWT = fromMaybe False $
isInfixOf "jwt_claims" . pdReturnType <$> returnType isInfixOf "jwt_claims" . pdReturnType <$> returnType
+2 -4
View File
@@ -31,7 +31,6 @@ import Options.Applicative
import Paths_postgrest (version) import Paths_postgrest (version)
import Protolude hiding (intercalate) import Protolude hiding (intercalate)
import Safe (readMay) import Safe (readMay)
import Web.JWT (Secret, secret)
-- | Data type to store all command line options -- | Data type to store all command line options
data AppConfig = AppConfig { data AppConfig = AppConfig {
@@ -41,7 +40,7 @@ data AppConfig = AppConfig {
, configSchema :: Text , configSchema :: Text
, configHost :: Text , configHost :: Text
, configPort :: Int , configPort :: Int
, configJwtSecret :: Secret , configJwtSecret :: Text
, configPool :: Int , configPool :: Int
, configMaxRows :: Maybe Integer , configMaxRows :: Maybe Integer
, configQuiet :: Bool , configQuiet :: Bool
@@ -55,8 +54,7 @@ argParser = AppConfig
<*> (toS <$> strOption (long "schema" <> short 's' <> help "schema to use for API routes" <> metavar "NAME" <> value "public" <> showDefault)) <*> (toS <$> strOption (long "schema" <> short 's' <> help "schema to use for API routes" <> metavar "NAME" <> value "public" <> showDefault))
<*> (toS <$> strOption (long "host" <> short 'l' <> help "hostname or ip on which to run HTTP server" <> metavar "HOST" <> value "*4" <> showDefault)) <*> (toS <$> strOption (long "host" <> short 'l' <> help "hostname or ip on which to run HTTP server" <> metavar "HOST" <> value "*4" <> showDefault))
<*> 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)
<*> (secret . toS <$> <*> (toS <$> strOption (long "jwt-secret" <> short 'j' <> help "secret used to encrypt and decrypt JWT tokens" <> metavar "SECRET"))
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)
<*> (readMay <$> strOption (long "max-rows" <> short 'm' <> help "max rows in response" <> metavar "COUNT" <> value "infinity" <> showDefault)) <*> (readMay <$> strOption (long "max-rows" <> short 'm' <> help "max rows in response" <> metavar "COUNT" <> value "infinity" <> showDefault))
<*> pure False <*> pure False
+4 -5
View File
@@ -8,7 +8,6 @@ import Data.CaseInsensitive (CI(..))
import Text.Regex.TDFA ((=~)) import Text.Regex.TDFA ((=~))
import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Char8 as BS
import System.Process (readProcess) import System.Process (readProcess)
import Web.JWT (secret)
import PostgREST.Config (AppConfig(..)) import PostgREST.Config (AppConfig(..))
@@ -52,19 +51,19 @@ testDbConn = "postgres://postgrest_test_authenticator@localhost:5432/postgrest_t
testCfg :: AppConfig testCfg :: AppConfig
testCfg = testCfg =
AppConfig testDbConn "postgrest_test_anonymous" Nothing "test" "localhost" 3000 (secret "safe") 10 Nothing True AppConfig testDbConn "postgrest_test_anonymous" Nothing "test" "localhost" 3000 "safe" 10 Nothing True
testUnicodeCfg :: AppConfig testUnicodeCfg :: AppConfig
testUnicodeCfg = testUnicodeCfg =
AppConfig testDbConn "postgrest_test_anonymous" Nothing "تست" "localhost" 3000 (secret "safe") 10 Nothing True AppConfig testDbConn "postgrest_test_anonymous" Nothing "تست" "localhost" 3000 "safe" 10 Nothing True
testLtdRowsCfg :: AppConfig testLtdRowsCfg :: AppConfig
testLtdRowsCfg = testLtdRowsCfg =
AppConfig testDbConn "postgrest_test_anonymous" Nothing "test" "localhost" 3000 (secret "safe") 10 (Just 2) True AppConfig testDbConn "postgrest_test_anonymous" Nothing "test" "localhost" 3000 "safe" 10 (Just 2) True
testProxyCfg :: AppConfig testProxyCfg :: AppConfig
testProxyCfg = testProxyCfg =
AppConfig testDbConn "postgrest_test_anonymous" (Just "https://postgrest.com/openapi.json") "test" "localhost" 3000 (secret "safe") 10 Nothing True AppConfig testDbConn "postgrest_test_anonymous" (Just "https://postgrest.com/openapi.json") "test" "localhost" 3000 "safe" 10 Nothing True
setupDb :: IO () setupDb :: IO ()
setupDb = do setupDb = do