From 6750a5c44d7806c9a50b3c83bf40ea4b3b82ccd9 Mon Sep 17 00:00:00 2001 From: steve-chavez Date: Wed, 17 Feb 2021 20:43:05 -0500 Subject: [PATCH] Restrict db settings to current db and global Global settings are overriden by database specific settings if they share common ones. --- src/PostgREST/Statements.hs | 13 +++++++++---- test/fixtures/roles.sql | 9 +++++++++ .../configs/expected/no-defaults-with-db.config | 4 ++-- test/io-tests/test_io.py | 4 ++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/PostgREST/Statements.hs b/src/PostgREST/Statements.hs index 7bfebfa3c..9c2422db0 100644 --- a/src/PostgREST/Statements.hs +++ b/src/PostgREST/Statements.hs @@ -195,18 +195,23 @@ decodeGucHeaders = first (const GucHeadersError) . JSON.eitherDecode . toS <$> H decodeGucStatus :: HD.Value (Either Error (Maybe Status)) decodeGucStatus = first (const GucStatusError) . fmap (Just . toEnum . fst) . decimal <$> HD.text --- | Get db settings from the connection role. Only used for configuration. +-- | Get db settings from the connection role. Global settings will be overridden by database specific settings. dbSettingsStatement :: H.Statement () [(Text, Text)] dbSettingsStatement = H.Statement sql HE.noParams decodeSettings False where sql = [q| with role_setting as ( - select unnest(setconfig) as setting from pg_catalog.pg_db_role_setting where setrole = current_user::regrole::oid + select setdatabase, unnest(setconfig) as setting from pg_catalog.pg_db_role_setting + where setrole = current_user::regrole::oid + and setdatabase in (0, (select oid from pg_catalog.pg_database where datname = current_catalog)) ), kv_settings as ( - select split_part(setting, '=', 1) as key, split_part(setting, '=', 2) as value from role_setting + select setdatabase, split_part(setting, '=', 1) as k, split_part(setting, '=', 2) as value from role_setting + where setting like 'pgrst.%' ) - select replace(key, 'pgrst.', '') as key, value from kv_settings where key like 'pgrst.%'; + select distinct on (key) replace(k, 'pgrst.', '') as key, value + from kv_settings + order by key, setdatabase desc; |] decodeSettings = HD.rowList $ (,) <$> column HD.text <*> column HD.text diff --git a/test/fixtures/roles.sql b/test/fixtures/roles.sql index dd3677dab..f0c7537b3 100644 --- a/test/fixtures/roles.sql +++ b/test/fixtures/roles.sql @@ -21,6 +21,15 @@ ALTER ROLE postgrest_test_authenticator SET pgrst."db_pre_request" = 'test.custo ALTER ROLE postgrest_test_authenticator SET pgrst."db_max_rows" = '1000'; ALTER ROLE postgrest_test_authenticator SET pgrst."db_extra_search_path" = 'public, extensions'; +-- override with database specific setting +ALTER ROLE postgrest_test_authenticator IN DATABASE :DBNAME SET pgrst."jwt_secret" = 'OVERRIDEREALLYREALLYREALLYREALLYVERYSAFE'; +ALTER ROLE postgrest_test_authenticator IN DATABASE :DBNAME SET pgrst."db_extra_search_path" = 'public, extensions, private'; + +-- other database settings that should be ignored +DROP DATABASE IF EXISTS other; +CREATE DATABASE other; +ALTER ROLE postgrest_test_authenticator IN DATABASE other SET pgrst."db_max_rows" = '1111'; + -- non-reloadable configs for io tests ALTER ROLE postgrest_test_authenticator SET pgrst."server_host" = 'ignored'; ALTER ROLE postgrest_test_authenticator SET pgrst."server_port" = 'ignored'; diff --git a/test/io-tests/configs/expected/no-defaults-with-db.config b/test/io-tests/configs/expected/no-defaults-with-db.config index 670178ff3..8bfe75458 100644 --- a/test/io-tests/configs/expected/no-defaults-with-db.config +++ b/test/io-tests/configs/expected/no-defaults-with-db.config @@ -1,7 +1,7 @@ db-anon-role = "postgrest_test_anonymous" db-channel = "postgrest" db-channel-enabled = true -db-extra-search-path = "public,extensions" +db-extra-search-path = "public,extensions,private" db-max-rows = 1000 db-pool = 1 db-pool-timeout = 100 @@ -14,7 +14,7 @@ db-tx-end = "commit-allow-override" db-uri = "" jwt-aud = "https://example.org" jwt-role-claim-key = ".\"a\".\"role\"" -jwt-secret = "REALLYREALLYREALLYREALLYVERYSAFE" +jwt-secret = "OVERRIDEREALLYREALLYREALLYREALLYVERYSAFE" jwt-secret-is-base64 = true log-level = "info" openapi-server-proxy-uri = "https://example.org/api" diff --git a/test/io-tests/test_io.py b/test/io-tests/test_io.py index fcf7d3e6c..2b1332ce4 100644 --- a/test/io-tests/test_io.py +++ b/test/io-tests/test_io.py @@ -309,10 +309,10 @@ def test_read_db_setting(defaultenv): "PGRST_DB_LOAD_GUC_CONFIG": "true", } with run(env=env) as postgrest: - uri = "/rpc/get_guc_value?name=pgrst.db_max_rows" + uri = "/rpc/get_guc_value?name=pgrst.jwt_secret" response = postgrest.session.get(uri) - assert response.text == '"1000"' + assert response.text == '"OVERRIDEREALLYREALLYREALLYREALLYVERYSAFE"' @pytest.mark.parametrize(