refactor: whitelist in-db config settings
This commit is contained in:
committed by
Steve Chavez
parent
009250006e
commit
8a3686d86b
+3
-10
@@ -358,21 +358,14 @@ parser optPath env dbSettings roleSettings =
|
|||||||
(C.Key -> C.Parser C.Value a -> C.Parser C.Config b) ->
|
(C.Key -> C.Parser C.Value a -> C.Parser C.Config b) ->
|
||||||
C.Key -> (C.Value -> a) -> C.Parser C.Config b
|
C.Key -> (C.Value -> a) -> C.Parser C.Config b
|
||||||
overrideFromDbOrEnvironment necessity key coercion =
|
overrideFromDbOrEnvironment necessity key coercion =
|
||||||
case reloadableDbSetting <|> M.lookup envVarName env of
|
case dbConf <|> M.lookup envVarName env of
|
||||||
Just dbOrEnvVal -> pure $ justIfMaybe $ coercion $ C.String dbOrEnvVal
|
Just dbOrEnvVal -> pure $ justIfMaybe $ coercion $ C.String dbOrEnvVal
|
||||||
Nothing -> necessity key (coercion <$> C.value)
|
Nothing -> necessity key (coercion <$> C.value)
|
||||||
where
|
where
|
||||||
dashToUnderscore '-' = '_'
|
dashToUnderscore '-' = '_'
|
||||||
dashToUnderscore c = c
|
dashToUnderscore c = c
|
||||||
envVarName = "PGRST_" <> (toUpper . dashToUnderscore <$> toS key)
|
envVarName = "PGRST_" <> (toUpper . dashToUnderscore <$> toS key)
|
||||||
reloadableDbSetting =
|
dbConf = lookup (T.pack $ dashToUnderscore <$> toS key) dbSettings
|
||||||
let dbSettingName = T.pack $ dashToUnderscore <$> toS key in
|
|
||||||
if dbSettingName `notElem` [
|
|
||||||
"server_host", "server_port", "server_unix_socket", "server_unix_socket_mode", "admin_server_port", "log_level",
|
|
||||||
"db_uri", "db_channel_enabled", "db_channel", "db_pool", "db_pool_acquisition_timeout",
|
|
||||||
"db_pool_max_lifetime", "db_pool_max_idletime", "db_config"]
|
|
||||||
then lookup dbSettingName dbSettings
|
|
||||||
else Nothing
|
|
||||||
|
|
||||||
coerceText :: C.Value -> Text
|
coerceText :: C.Value -> Text
|
||||||
coerceText (C.String s) = s
|
coerceText (C.String s) = s
|
||||||
|
|||||||
@@ -21,12 +21,40 @@ import qualified Hasql.Statement as SQL
|
|||||||
import qualified Hasql.Transaction as SQL
|
import qualified Hasql.Transaction as SQL
|
||||||
import qualified Hasql.Transaction.Sessions as SQL
|
import qualified Hasql.Transaction.Sessions as SQL
|
||||||
|
|
||||||
import Text.InterpolatedString.Perl6 (q)
|
import Text.InterpolatedString.Perl6 (q, qc)
|
||||||
|
|
||||||
import Protolude
|
import Protolude
|
||||||
|
|
||||||
type RoleSettings = (HM.HashMap ByteString (HM.HashMap ByteString ByteString))
|
type RoleSettings = (HM.HashMap ByteString (HM.HashMap ByteString ByteString))
|
||||||
|
|
||||||
|
prefix :: Text
|
||||||
|
prefix = "pgrst."
|
||||||
|
|
||||||
|
-- | In-db settings names
|
||||||
|
dbSettingsNames :: [Text]
|
||||||
|
dbSettingsNames =
|
||||||
|
(prefix <>) <$>
|
||||||
|
["db_anon_role"
|
||||||
|
,"db_extra_search_path"
|
||||||
|
,"db_max_rows"
|
||||||
|
,"db_plan_enabled"
|
||||||
|
,"db_pre_request"
|
||||||
|
,"db_prepared_statements"
|
||||||
|
,"db_root_spec"
|
||||||
|
,"db_schemas"
|
||||||
|
,"db_tx_end"
|
||||||
|
,"db_use_legacy_gucs"
|
||||||
|
,"jwt_aud"
|
||||||
|
,"jwt_role_claim_key"
|
||||||
|
,"jwt_secret"
|
||||||
|
,"jwt_secret_is_base64"
|
||||||
|
,"openapi_mode"
|
||||||
|
,"openapi_security_active"
|
||||||
|
,"openapi_server_proxy_uri"
|
||||||
|
,"raw_media_types"
|
||||||
|
,"server_trace_header"
|
||||||
|
]
|
||||||
|
|
||||||
queryPgVersion :: Bool -> Session PgVersion
|
queryPgVersion :: Bool -> Session PgVersion
|
||||||
queryPgVersion prepared = statement mempty $ pgVersionStatement prepared
|
queryPgVersion prepared = statement mempty $ pgVersionStatement prepared
|
||||||
|
|
||||||
@@ -39,33 +67,40 @@ pgVersionStatement = SQL.Statement sql HE.noParams versionRow
|
|||||||
queryDbSettings :: Bool -> Session [(Text, Text)]
|
queryDbSettings :: Bool -> Session [(Text, Text)]
|
||||||
queryDbSettings prepared =
|
queryDbSettings prepared =
|
||||||
let transaction = if prepared then SQL.transaction else SQL.unpreparedTransaction in
|
let transaction = if prepared then SQL.transaction else SQL.unpreparedTransaction in
|
||||||
transaction SQL.ReadCommitted SQL.Read $ SQL.statement mempty $ dbSettingsStatement prepared
|
transaction SQL.ReadCommitted SQL.Read $ SQL.statement dbSettingsNames $ dbSettingsStatement prepared
|
||||||
|
|
||||||
-- | Get db settings from the connection role. Global settings will be overridden by database specific settings.
|
-- | Get db settings from the connection role. Global settings will be overridden by database specific settings.
|
||||||
dbSettingsStatement :: Bool -> SQL.Statement () [(Text, Text)]
|
-- i.e. Doing:
|
||||||
dbSettingsStatement = SQL.Statement sql HE.noParams decodeSettings
|
-- ALTER ROLE authenticator IN DATABASE postgres SET <prefix>jwt_aud = 'val';
|
||||||
|
-- ALTER ROLE authenticator SET <prefix>jwt_aud = 'overridden';
|
||||||
|
-- Will result in <prefix>jwt_aud = 'overridden'
|
||||||
|
--
|
||||||
|
-- A setting on the database only will have no effect
|
||||||
|
-- ALTER DATABASE postgres SET <prefix>jwt_aud = 'xx'
|
||||||
|
dbSettingsStatement :: Bool -> SQL.Statement [Text] [(Text, Text)]
|
||||||
|
dbSettingsStatement = SQL.Statement sql (arrayParam HE.text) decodeSettings
|
||||||
where
|
where
|
||||||
sql = [q|
|
sql = [qc|
|
||||||
WITH
|
WITH
|
||||||
role_setting (database, setting) AS (
|
role_setting AS (
|
||||||
SELECT setdatabase,
|
SELECT setdatabase as database,
|
||||||
unnest(setconfig)
|
unnest(setconfig) as setting
|
||||||
FROM pg_catalog.pg_db_role_setting
|
FROM pg_catalog.pg_db_role_setting
|
||||||
WHERE setrole = CURRENT_USER::regrole::oid
|
WHERE setrole = CURRENT_USER::regrole::oid
|
||||||
AND setdatabase IN (0, (SELECT oid FROM pg_catalog.pg_database WHERE datname = CURRENT_CATALOG))
|
AND setdatabase IN (0, (SELECT oid FROM pg_catalog.pg_database WHERE datname = CURRENT_CATALOG))
|
||||||
),
|
),
|
||||||
kv_settings (database, k, v) AS (
|
kv_settings AS (
|
||||||
SELECT database,
|
SELECT database,
|
||||||
substr(setting, 1, strpos(setting, '=') - 1),
|
substr(setting, 1, strpos(setting, '=') - 1) as k,
|
||||||
substr(setting, strpos(setting, '=') + 1)
|
substr(setting, strpos(setting, '=') + 1) as v
|
||||||
FROM role_setting
|
FROM role_setting
|
||||||
WHERE setting LIKE 'pgrst.%'
|
|
||||||
)
|
)
|
||||||
SELECT DISTINCT ON (key)
|
SELECT DISTINCT ON (key)
|
||||||
replace(k, 'pgrst.', '') AS key,
|
replace(k, '{prefix}', '') AS key,
|
||||||
v AS value
|
v AS value
|
||||||
FROM kv_settings
|
FROM kv_settings
|
||||||
ORDER BY key, database DESC;
|
WHERE k = ANY($1)
|
||||||
|
ORDER BY key, database DESC;
|
||||||
|]
|
|]
|
||||||
decodeSettings = HD.rowList $ (,) <$> column HD.text <*> column HD.text
|
decodeSettings = HD.rowList $ (,) <$> column HD.text <*> column HD.text
|
||||||
|
|
||||||
@@ -111,3 +146,9 @@ compositeArrayColumn = arrayColumn . HD.composite
|
|||||||
|
|
||||||
arrayColumn :: HD.Value a -> HD.Row [a]
|
arrayColumn :: HD.Value a -> HD.Row [a]
|
||||||
arrayColumn = column . HD.listArray . HD.nonNullable
|
arrayColumn = column . HD.listArray . HD.nonNullable
|
||||||
|
|
||||||
|
param :: HE.Value a -> HE.Params a
|
||||||
|
param = HE.param . HE.nonNullable
|
||||||
|
|
||||||
|
arrayParam :: HE.Value a -> HE.Params [a]
|
||||||
|
arrayParam = param . HE.foldableArray . HE.nonNullable
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ ALTER ROLE db_config_authenticator SET pgrst.db_channel_enabled = 'ignored';
|
|||||||
ALTER ROLE db_config_authenticator SET pgrst.db_channel = 'ignored';
|
ALTER ROLE db_config_authenticator SET pgrst.db_channel = 'ignored';
|
||||||
ALTER ROLE db_config_authenticator SET pgrst.db_pool = 'ignored';
|
ALTER ROLE db_config_authenticator SET pgrst.db_pool = 'ignored';
|
||||||
ALTER ROLE db_config_authenticator SET pgrst.db_pool_timeout = 'ignored';
|
ALTER ROLE db_config_authenticator SET pgrst.db_pool_timeout = 'ignored';
|
||||||
|
ALTER ROLE db_config_authenticator SET pgrst.db_pool_acquisition_timeout = 'ignored';
|
||||||
|
ALTER ROLE db_config_authenticator SET pgrst.db_pool_max_lifetime = 'ignored';
|
||||||
|
ALTER ROLE db_config_authenticator SET pgrst.db_pool_max_idletime = 'ignored';
|
||||||
ALTER ROLE db_config_authenticator SET pgrst.db_config = 'ignored';
|
ALTER ROLE db_config_authenticator SET pgrst.db_config = 'ignored';
|
||||||
|
|
||||||
-- other authenticator reloadable config options
|
-- other authenticator reloadable config options
|
||||||
|
|||||||
Reference in New Issue
Block a user