feat: renamed config options with prefixes; added aliases for old names

* secret-is-base64 -> jwt-secret-is-base64
* role-claim-key -> jwt-role-claim-key
* max-rows -> db-max-rows
* pre-request -> db-pre-request
* root-spec -> db-root-spec
* db-schema -> db-schemas

This is not a breaking change, because aliases are added as well.

refactor: sorted all config keys alphabetically where applicable
This commit is contained in:
Wolfgang Walther
2020-12-06 21:59:03 +01:00
committed by Wolfgang Walther
parent ab3375998d
commit ed58511de3
21 changed files with 269 additions and 224 deletions
+10 -10
View File
@@ -75,25 +75,25 @@ postgrest logLev refConf refDbStructure pool getTime connWorker =
Nothing -> respond . errorResponseFor $ ConnectionLostError
Just dbStructure -> do
response <- do
let apiReq = userApiRequest (configSchemas conf) (configRootSpec conf) dbStructure req body
let apiReq = userApiRequest (configDbSchemas conf) (configDbRootSpec conf) dbStructure req body
case apiReq of
Left err -> return . errorResponseFor $ err
Right apiRequest -> do
-- The jwt must be checked before touching the db.
attempt <- attemptJwtClaims (configJWKS conf) (configJwtAudience conf) (toS $ iJWT apiRequest) time (rightToMaybe $ configRoleClaimKey conf)
attempt <- attemptJwtClaims (configJWKS conf) (configJwtAudience conf) (toS $ iJWT apiRequest) time (rightToMaybe $ configJwtRoleClaimKey conf)
case jwtClaims attempt of
Left errJwt -> return . errorResponseFor $ errJwt
Right claims -> do
let
authed = containsRole claims
shouldCommit = configTxAllowOverride conf && iPreferTransaction apiRequest == Just Commit
shouldRollback = configTxAllowOverride conf && iPreferTransaction apiRequest == Just Rollback
shouldCommit = configDbTxAllowOverride conf && iPreferTransaction apiRequest == Just Commit
shouldRollback = configDbTxAllowOverride conf && iPreferTransaction apiRequest == Just Rollback
preferenceApplied
| shouldCommit = addHeadersIfNotIncluded [(hPreferenceApplied, BS.pack (show Commit))]
| shouldRollback = addHeadersIfNotIncluded [(hPreferenceApplied, BS.pack (show Rollback))]
| otherwise = identity
handleReq = do
when (shouldRollback || (configTxRollbackAll conf && not shouldCommit)) HT.condemn
when (shouldRollback || (configDbTxRollbackAll conf && not shouldCommit)) HT.condemn
mapResponseHeaders preferenceApplied <$> runPgLocals conf claims (app dbStructure conf) apiRequest
dbResp <- P.use pool $ HT.transaction HT.ReadCommitted (txMode apiRequest) handleReq
return $ either (errorResponseFor . PgError authed) identity dbResp
@@ -320,9 +320,9 @@ app dbStructure conf apiRequest =
return $ responseLBS status headers rBody
(ActionInspect headersOnly, TargetDefaultSpec tSchema) -> do
let host = configHost conf
port = toInteger $ configPort conf
proxy = pickProxy $ toS <$> configOpenAPIProxyUri conf
let host = configServerHost conf
port = toInteger $ configServerPort conf
proxy = pickProxy $ toS <$> configOpenApiServerProxyUri conf
uri Nothing = ("http", host, port, "/")
uri (Just Proxy { proxyScheme = s, proxyHost = h, proxyPort = p, proxyPath = b }) = (s, h, p, b)
uri' = uri proxy
@@ -340,8 +340,8 @@ app dbStructure conf apiRequest =
where
notFound = responseLBS status404 [] ""
maxRows = configMaxRows conf
prepared = configDbPrepared conf
maxRows = configDbMaxRows conf
prepared = configDbPreparedStatements conf
exactCount = iPreferCount apiRequest == Just ExactCount
estimatedCount = iPreferCount apiRequest == Just EstimatedCount
plannedCount = iPreferCount apiRequest == Just PlannedCount
+111 -99
View File
@@ -22,7 +22,7 @@ module PostgREST.Config ( prettyVersion
, CLI (..)
, Command (..)
, AppConfig (..)
, configPoolTimeout'
, configDbPoolTimeout'
, dumpAppConfig
, readCLIShowHelp
, readValidateConfig
@@ -78,46 +78,39 @@ data Command = CmdRun | CmdDumpConfig deriving (Eq)
-- | Config file settings for the server
data AppConfig = AppConfig {
configDbUri :: Text
, configAnonRole :: Text
, configOpenAPIProxyUri :: Maybe Text
, configSchemas :: NonEmpty Text
, configHost :: Text
, configPort :: Int
, configSocket :: Maybe FilePath
, configSocketMode :: Either Text FileMode
, configDbChannel :: Text
, configDbChannelEnabled :: Bool
, configJwtSecret :: Maybe B.ByteString
, configJwtSecretIsBase64 :: Bool
, configJwtAudience :: Maybe StringOrURI
, configPoolSize :: Int
, configPoolTimeout :: Int
, configMaxRows :: Maybe Integer
, configPreReq :: Maybe Text
, configSettings :: [(Text, Text)]
, configRoleClaimKey :: Either Text JSPath
, configExtraSearchPath :: [Text]
, configRootSpec :: Maybe Text
, configRawMediaTypes :: [B.ByteString]
, configJWKS :: Maybe JWKSet
, configLogLevel :: LogLevel
, configTxRollbackAll :: Bool
, configTxAllowOverride :: Bool
, configDbPrepared :: Bool
configAppSettings :: [(Text, Text)]
, configDbAnonRole :: Text
, configDbChannel :: Text
, configDbChannelEnabled :: Bool
, configDbExtraSearchPath :: [Text]
, configDbMaxRows :: Maybe Integer
, configDbPoolSize :: Int
, configDbPoolTimeout :: Int
, configDbPreRequest :: Maybe Text
, configDbPreparedStatements :: Bool
, configDbRootSpec :: Maybe Text
, configDbSchemas :: NonEmpty Text
, configDbTxAllowOverride :: Bool
, configDbTxRollbackAll :: Bool
, configDbUri :: Text
, configJWKS :: Maybe JWKSet
, configJwtAudience :: Maybe StringOrURI
, configJwtRoleClaimKey :: Either Text JSPath
, configJwtSecret :: Maybe B.ByteString
, configJwtSecretIsBase64 :: Bool
, configLogLevel :: LogLevel
, configOpenApiServerProxyUri :: Maybe Text
, configRawMediaTypes :: [B.ByteString]
, configServerHost :: Text
, configServerPort :: Int
, configServerUnixSocket :: Maybe FilePath
, configServerUnixSocketMode :: Either Text FileMode
}
deriving (Show)
configPoolTimeout' :: (Fractional a) => AppConfig -> a
configPoolTimeout' =
fromRational . toRational . configPoolTimeout
configDbPoolTimeout' :: (Fractional a) => AppConfig -> a
configDbPoolTimeout' =
fromRational . toRational . configDbPoolTimeout
-- | User friendly version number
prettyVersion :: Text
@@ -179,6 +172,16 @@ readCLIShowHelp = customExecParser parserPrefs opts
|## extra schemas to add to the search_path of every request
|db-extra-search-path = "public"
|
|## limit rows in response
|# db-max-rows = 1000
|
|## stored proc to exec immediately after auth
|# db-pre-request = "stored_proc_name"
|
|## stored proc that overrides the root "/" spec
|## it must be inside the db-schema
|# db-root-spec = "stored_proc_name"
|
|## Notification channel for reloading the schema cache
|db-channel = "pgrst"
|
@@ -219,20 +222,10 @@ readCLIShowHelp = customExecParser parserPrefs opts
|## (use "@filename" to load from separate file)
|# jwt-secret = "secret_with_at_least_32_characters"
|# jwt-aud = "your_audience_claim"
|secret-is-base64 = false
|jwt-secret-is-base64 = false
|
|## jspath to the role claim key
|role-claim-key = ".role"
|
|## limit rows in response
|# max-rows = 1000
|
|## stored proc to exec immediately after auth
|# pre-request = "stored_proc_name"
|
|## stored proc that overrides the root "/" spec
|## it must be inside the db-schema
|# root-spec = "stored_proc_name"
|jwt-role-claim-key = ".role"
|
|## content types to produce raw output
|# raw-media-types="image/png, image/jpg"
@@ -253,49 +246,49 @@ dumpAppConfig conf = do
-- apply conf to all pgrst settings
pgrstSettings = (\(k, v) -> (k, v conf)) <$>
[("db-uri", q . configDbUri)
,("db-schema", q . intercalate "," . toList . configSchemas)
,("db-anon-role", q . configAnonRole)
,("db-pool", show . configPoolSize)
,("db-pool-timeout", show . configPoolTimeout)
,("db-extra-search-path", q . intercalate "," . configExtraSearchPath)
[("db-anon-role", q . configDbAnonRole)
,("db-channel", q . configDbChannel)
,("db-channel-enabled", toLower . show . configDbChannelEnabled)
,("db-extra-search-path", q . intercalate "," . configDbExtraSearchPath)
,("db-max-rows", maybe "\"\"" show . configDbMaxRows)
,("db-pool", show . configDbPoolSize)
,("db-pool-timeout", show . configDbPoolTimeout)
,("db-pre-request", q . fromMaybe mempty . configDbPreRequest)
,("db-prepared-statements", toLower . show . configDbPreparedStatements)
,("db-root-spec", q . fromMaybe mempty . configDbRootSpec)
,("db-schemas", q . intercalate "," . toList . configDbSchemas)
,("db-tx-end", q . showTxEnd)
,("db-prepared-statements", toLower . show . configDbPrepared)
,("server-host", q . configHost)
,("server-port", show . configPort)
,("server-unix-socket", q . maybe mempty pack . configSocket)
,("server-unix-socket-mode", q . pack . showSocketMode)
,("openapi-server-proxy-uri", q . fromMaybe mempty . configOpenAPIProxyUri)
,("jwt-secret", q . toS . showJwtSecret)
,("db-uri", q . configDbUri)
,("jwt-aud", toS . encode . maybe "" toJSON . configJwtAudience)
,("secret-is-base64", toLower . show . configJwtSecretIsBase64)
,("role-claim-key", q . intercalate mempty . fmap show . fromRight' . configRoleClaimKey)
,("max-rows", maybe "\"\"" show . configMaxRows)
,("pre-request", q . fromMaybe mempty . configPreReq)
,("root-spec", q . fromMaybe mempty . configRootSpec)
,("raw-media-types", q . toS . B.intercalate "," . configRawMediaTypes)
,("jwt-role-claim-key", q . intercalate mempty . fmap show . fromRight' . configJwtRoleClaimKey)
,("jwt-secret", q . toS . showJwtSecret)
,("jwt-secret-is-base64", toLower . show . configJwtSecretIsBase64)
,("log-level", q . show . configLogLevel)
,("openapi-server-proxy-uri", q . fromMaybe mempty . configOpenApiServerProxyUri)
,("raw-media-types", q . toS . B.intercalate "," . configRawMediaTypes)
,("server-host", q . configServerHost)
,("server-port", show . configServerPort)
,("server-unix-socket", q . maybe mempty pack . configServerUnixSocket)
,("server-unix-socket-mode", q . pack . showSocketMode)
]
-- quote all app.settings
appSettings = second q <$> configSettings conf
appSettings = second q <$> configAppSettings conf
-- quote strings and replace " with \"
q s = "\"" <> replace "\"" "\\\"" s <> "\""
showTxEnd c = case (configTxRollbackAll c, configTxAllowOverride c) of
showTxEnd c = case (configDbTxRollbackAll c, configDbTxAllowOverride c) of
( False, False ) -> "commit"
( False, True ) -> "commit-allow-override"
( True , False ) -> "rollback"
( True , True ) -> "rollback-allow-override"
showSocketMode c = showOct (fromRight' $ configSocketMode c) ""
showJwtSecret c
| configJwtSecretIsBase64 c = B64.encode secret
| otherwise = toS secret
where
secret = fromMaybe mempty $ configJwtSecret c
showSocketMode c = showOct (fromRight' $ configServerUnixSocketMode c) ""
-- | Parse the config file
readAppConfig :: FilePath -> IO AppConfig
@@ -315,33 +308,40 @@ readAppConfig cfgPath = do
where
parseConfig =
AppConfig
<$> reqString "db-uri"
<$> (fmap (fmap coerceText) <$> C.subassocs "app.settings" C.value)
<*> reqString "db-anon-role"
<*> (fromMaybe "pgrst" <$> optString "db-channel")
<*> (fromMaybe False <$> optBool "db-channel-enabled")
<*> (maybe ["public"] splitOnCommas <$> optValue "db-extra-search-path")
<*> optWithAlias (optInt "db-max-rows")
(optInt "max-rows")
<*> (fromMaybe 10 <$> optInt "db-pool")
<*> (fromMaybe 10 <$> optInt "db-pool-timeout")
<*> optWithAlias (optString "db-pre-request")
(optString "pre-request")
<*> (fromMaybe True <$> optBool "db-prepared-statements")
<*> optWithAlias (optString "db-root-spec")
(optString "root-spec")
<*> (fromList . splitOnCommas <$> reqWithAlias (optValue "db-schemas")
(optValue "db-schema")
"missing key: either db-schemas or db-schema must be set")
<*> parseTxEnd "db-tx-end" snd
<*> parseTxEnd "db-tx-end" fst
<*> reqString "db-uri"
<*> pure Nothing
<*> parseJwtAudience "jwt-aud"
<*> (maybe (Right [JSPKey "role"]) parseRoleClaimKey <$> optWithAlias (optValue "jwt-role-claim-key")
(optValue "role-claim-key"))
<*> (fmap encodeUtf8 <$> optString "jwt-secret")
<*> (fromMaybe False <$> optWithAlias (optBool "jwt-secret-is-base64")
(optBool "secret-is-base64"))
<*> parseLogLevel "log-level"
<*> optString "openapi-server-proxy-uri"
<*> (fromList . splitOnCommas <$> reqValue "db-schema")
<*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types")
<*> (fromMaybe "!4" <$> optString "server-host")
<*> (fromMaybe 3000 <$> optInt "server-port")
<*> (fmap unpack <$> optString "server-unix-socket")
<*> parseSocketFileMode "server-unix-socket-mode"
<*> (fromMaybe "pgrst" <$> optString "db-channel")
<*> (fromMaybe False <$> optBool "db-channel-enabled")
<*> (fmap encodeUtf8 <$> optString "jwt-secret")
<*> (fromMaybe False <$> optBool "secret-is-base64")
<*> parseJwtAudience "jwt-aud"
<*> (fromMaybe 10 <$> optInt "db-pool")
<*> (fromMaybe 10 <$> optInt "db-pool-timeout")
<*> optInt "max-rows"
<*> optString "pre-request"
<*> (fmap (fmap coerceText) <$> C.subassocs "app.settings" C.value)
<*> (maybe (Right [JSPKey "role"]) parseRoleClaimKey <$> optValue "role-claim-key")
<*> (maybe ["public"] splitOnCommas <$> optValue "db-extra-search-path")
<*> optString "root-spec"
<*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types")
<*> pure Nothing
<*> parseLogLevel "log-level"
<*> parseTxEnd "db-tx-end" fst
<*> parseTxEnd "db-tx-end" snd
<*> (fromMaybe True <$> optBool "db-prepared-statements")
parseSocketFileMode :: C.Key -> C.Parser C.Config (Either Text FileMode)
parseSocketFileMode k =
@@ -388,12 +388,24 @@ readAppConfig cfgPath = do
Just "rollback-allow-override" -> pure $ f (True, True)
Just _ -> fail "Invalid transaction termination. Check your configuration."
reqWithAlias :: C.Parser C.Config (Maybe a) -> C.Parser C.Config (Maybe a) -> [Char] -> C.Parser C.Config a
reqWithAlias orig alias err =
orig >>= \case
Just v -> pure v
Nothing ->
alias >>= \case
Just v -> pure v
Nothing -> fail err
optWithAlias :: C.Parser C.Config (Maybe a) -> C.Parser C.Config (Maybe a) -> C.Parser C.Config (Maybe a)
optWithAlias orig alias =
orig >>= \case
Just v -> pure $ Just v
Nothing -> alias
reqString :: C.Key -> C.Parser C.Config Text
reqString k = C.required k C.string
reqValue :: C.Key -> C.Parser C.Config C.Value
reqValue k = C.required k C.value
optString :: C.Key -> C.Parser C.Config (Maybe Text)
optString k = mfilter (/= "") <$> C.optional k C.string
@@ -438,13 +450,13 @@ readValidateConfig :: FilePath -> IO AppConfig
readValidateConfig path = do
conf <- loadDbUriFile =<< loadSecretFile =<< readAppConfig path
-- Checks that the provided proxy uri is formated correctly
when (isMalformedProxyUri $ toS <$> configOpenAPIProxyUri conf) $
when (isMalformedProxyUri $ toS <$> configOpenApiServerProxyUri conf) $
panic
"Malformed proxy uri, a correct example: https://example.com:8443/basePath"
-- Checks that the provided jspath is valid
whenLeft (configRoleClaimKey conf) panic
whenLeft (configJwtRoleClaimKey conf) panic
-- Check the file mode is valid
whenLeft (configSocketMode conf) panic
whenLeft (configServerUnixSocketMode conf) panic
return $ conf { configJWKS = parseSecret <$> configJwtSecret conf}
{-|
+4 -4
View File
@@ -53,14 +53,14 @@ runPgLocals conf claims app req = do
headersSql = setLocalQuery "request.header." <$> iHeaders req
cookiesSql = setLocalQuery "request.cookie." <$> iCookies req
claimsSql = setLocalQuery "request.jwt.claim." <$> [(c,unquoted v) | (c,v) <- M.toList claimsWithRole]
appSettingsSql = setLocalQuery mempty <$> configSettings conf
appSettingsSql = setLocalQuery mempty <$> configAppSettings conf
setRoleSql = maybeToList $ (\x ->
setLocalQuery mempty ("role", unquoted x)) <$> M.lookup "role" claimsWithRole
setSearchPathSql = setLocalSearchPathQuery (iSchema req : configExtraSearchPath conf)
setSearchPathSql = setLocalSearchPathQuery (iSchema req : configDbExtraSearchPath conf)
-- role claim defaults to anon if not specified in jwt
claimsWithRole = M.union claims (M.singleton "role" anon)
anon = JSON.String . toS $ configAnonRole conf
preReq = (\f -> "select " <> toS f <> "();") <$> configPreReq conf
anon = JSON.String . toS $ configDbAnonRole conf
preReq = (\f -> "select " <> toS f <> "();") <$> configDbPreRequest conf
-- | Log in apache format. Only requests that have a status greater than minStatus are logged.
-- | There's no way to filter logs in the apache format on wai-extra: https://hackage.haskell.org/package/wai-extra-3.0.29.2/docs/Network-Wai-Middleware-RequestLogger.html#t:OutputFormat.