From bf758698b34bd8fdf2ec1c6c6412233ddb2019dc Mon Sep 17 00:00:00 2001 From: Taimoor Zaeem Date: Mon, 27 Apr 2026 12:16:05 +0500 Subject: [PATCH] fix: login with uppercase and mixed case role names PostgREST failed when querying role settings where current role name contained uppercase letters. This commit resolves it by quoting the CURRENT_USER. Signed-off-by: Taimoor Zaeem --- CHANGELOG.md | 1 + nix/tools/withTools.nix | 2 +- src/PostgREST/Config/Database.hs | 6 +++--- test/io/fixtures/big_schema.sql | 2 +- test/io/fixtures/replica.sql | 2 +- test/io/fixtures/roles.sql | 4 ++-- test/io/fixtures/schema.sql | 18 +++++++++--------- test/load/fixtures.sql | 4 ++-- test/observability/fixtures/roles.sql | 2 +- test/spec/fixtures/roles.sql | 2 +- 10 files changed, 22 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6503d47e6..ab1fa409d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. From versio ### Fixed - Shutdown should wait for in flight requests by @mkleczek in #4702 +- Fix login with uppercase and mixed case role names by @taimoorzaeem in #4678 ### Changed diff --git a/nix/tools/withTools.nix b/nix/tools/withTools.nix index b18b1ad52..6b17ef6f4 100644 --- a/nix/tools/withTools.nix +++ b/nix/tools/withTools.nix @@ -24,7 +24,7 @@ let "ARG_OPTIONAL_SINGLE([fixtures], [f], [SQL file to load fixtures from])" "ARG_POSITIONAL_SINGLE([command], [Command to run])" "ARG_LEFTOVERS([command arguments])" - "ARG_USE_ENV([PGUSER], [postgrest_test_authenticator], [Authenticator PG role])" + "ARG_USE_ENV([PGUSER], [Postgrest_Test_Authenticator], [Authenticator PG role])" # user is written in mixed case to implicitly test that it is being properly quoted in schema cache queries "ARG_USE_ENV([PGDATABASE], [postgres], [PG database name])" "ARG_USE_ENV([PGRST_DB_SCHEMAS], [test], [Schema to expose])" "ARG_USE_ENV([PGTZ], [utc], [Timezone to use])" diff --git a/src/PostgREST/Config/Database.hs b/src/PostgREST/Config/Database.hs index 3aeb93ba5..e38f34876 100644 --- a/src/PostgREST/Config/Database.hs +++ b/src/PostgREST/Config/Database.hs @@ -102,7 +102,7 @@ queryDbSettings preConfFunc = SELECT setdatabase as database, unnest(setconfig) as setting FROM pg_catalog.pg_db_role_setting - WHERE setrole = CURRENT_USER::regrole::oid + WHERE setrole = quote_ident(CURRENT_USER)::regrole::oid AND setdatabase IN (0, (SELECT oid FROM pg_catalog.pg_database WHERE datname = CURRENT_CATALOG)) ), kv_settings AS ( @@ -142,7 +142,7 @@ queryRoleSettings pgVer = select r.rolname, unnest(r.rolconfig) as setting from pg_auth_members m join pg_roles r on r.oid = m.roleid - where member = current_user::regrole::oid + where member = quote_ident(current_user)::regrole::oid ), kv_settings AS ( SELECT @@ -167,7 +167,7 @@ queryRoleSettings pgVer = |] hasParameterPrivilege - | pgVer >= pgVersion150 = "or has_parameter_privilege(current_user::regrole::oid, ps.name, 'set')" + | pgVer >= pgVersion150 = "or has_parameter_privilege(quote_ident(current_user)::regrole::oid, ps.name, 'set')" | otherwise = "" processRows :: [(Text, Maybe Text, [(Text, Text)])] -> (RoleSettings, RoleIsolationLvl) diff --git a/test/io/fixtures/big_schema.sql b/test/io/fixtures/big_schema.sql index 6984164a6..559b434df 100644 --- a/test/io/fixtures/big_schema.sql +++ b/test/io/fixtures/big_schema.sql @@ -11399,7 +11399,7 @@ $$; DROP ROLE IF EXISTS postgrest_test_anonymous; CREATE ROLE postgrest_test_anonymous; -GRANT postgrest_test_anonymous TO :PGUSER; +GRANT postgrest_test_anonymous TO :"PGUSER"; GRANT USAGE ON SCHEMA apflora TO postgrest_test_anonymous; GRANT USAGE ON SCHEMA fuzzysearch TO postgrest_test_anonymous; diff --git a/test/io/fixtures/replica.sql b/test/io/fixtures/replica.sql index deffbec06..bf765fdb3 100644 --- a/test/io/fixtures/replica.sql +++ b/test/io/fixtures/replica.sql @@ -13,7 +13,7 @@ create table replica.items as select x as id from generate_series(1, 10) x; DROP ROLE IF EXISTS postgrest_test_anonymous; CREATE ROLE postgrest_test_anonymous; -GRANT postgrest_test_anonymous TO :PGUSER; +GRANT postgrest_test_anonymous TO :"PGUSER"; GRANT USAGE ON SCHEMA replica TO postgrest_test_anonymous; diff --git a/test/io/fixtures/roles.sql b/test/io/fixtures/roles.sql index 1a6382253..61070d7a1 100644 --- a/test/io/fixtures/roles.sql +++ b/test/io/fixtures/roles.sql @@ -12,9 +12,9 @@ CREATE ROLE postgrest_test_w_superuser_settings; GRANT postgrest_test_anonymous, postgrest_test_author, postgrest_test_serializable, postgrest_test_repeatable_read, - postgrest_test_w_superuser_settings TO :PGUSER; + postgrest_test_w_superuser_settings TO :"PGUSER"; -ALTER ROLE :PGUSER SET pgrst.db_anon_role = 'postgrest_test_anonymous'; +ALTER ROLE :"PGUSER" SET pgrst.db_anon_role = 'postgrest_test_anonymous'; ALTER ROLE postgrest_test_serializable SET default_transaction_isolation = 'serializable'; ALTER ROLE postgrest_test_repeatable_read SET default_transaction_isolation = 'REPEATABLE READ'; diff --git a/test/io/fixtures/schema.sql b/test/io/fixtures/schema.sql index 630fca3cf..0ca35079e 100644 --- a/test/io/fixtures/schema.sql +++ b/test/io/fixtures/schema.sql @@ -42,7 +42,7 @@ VALUES (1, 'pulp fiction', 1), DO $do$BEGIN IF (SELECT current_setting('server_version_num')::INT >= 150000) THEN ALTER ROLE postgrest_test_w_superuser_settings SET log_min_duration_sample = 12345; - GRANT SET ON PARAMETER log_min_duration_sample to postgrest_test_authenticator; + GRANT SET ON PARAMETER log_min_duration_sample to "Postgrest_Test_Authenticator"; END IF; END$do$; @@ -61,7 +61,7 @@ $$ language sql; create function change_max_rows_config(val int, notify bool default false) returns void as $_$ begin execute format($$ - alter role postgrest_test_authenticator set pgrst.db_max_rows = %L; + alter role "Postgrest_Test_Authenticator" set pgrst.db_max_rows = %L; $$, val); if notify then perform pg_notify('pgrst', 'reload config'); @@ -70,13 +70,13 @@ end $_$ volatile security definer language plpgsql ; create function reset_max_rows_config() returns void as $_$ begin - alter role postgrest_test_authenticator reset pgrst.db_max_rows; + alter role "Postgrest_Test_Authenticator" reset pgrst.db_max_rows; end $_$ volatile security definer language plpgsql ; create function change_db_schema_and_full_reload(schemas text) returns void as $_$ begin execute format($$ - alter role postgrest_test_authenticator set pgrst.db_schemas = %L; + alter role "Postgrest_Test_Authenticator" set pgrst.db_schemas = %L; $$, schemas); perform pg_notify('pgrst', 'reload config'); perform pg_notify('pgrst', 'reload schema'); @@ -84,14 +84,14 @@ end $_$ volatile security definer language plpgsql ; create function v1.reset_db_schema_config() returns void as $_$ begin - alter role postgrest_test_authenticator reset pgrst.db_schemas; + alter role "Postgrest_Test_Authenticator" reset pgrst.db_schemas; perform pg_notify('pgrst', 'reload config'); perform pg_notify('pgrst', 'reload schema'); end $_$ volatile security definer language plpgsql ; create function invalid_role_claim_key_reload() returns void as $_$ begin - alter role postgrest_test_authenticator set pgrst.jwt_role_claim_key = 'test'; + alter role "Postgrest_Test_Authenticator" set pgrst.jwt_role_claim_key = 'test'; perform pg_notify('pgrst', 'reload config'); end $_$ volatile security definer language plpgsql ; @@ -104,7 +104,7 @@ $_$ language sql; create function reset_invalid_role_claim_key() returns void as $_$ begin - alter role postgrest_test_authenticator reset pgrst.jwt_role_claim_key; + alter role "Postgrest_Test_Authenticator" reset pgrst.jwt_role_claim_key; perform pg_notify('pgrst', 'reload config'); end $_$ volatile security definer language plpgsql ; @@ -229,12 +229,12 @@ $$ language sql; create function change_db_schemas_config() returns void as $_$ begin - alter role postgrest_test_authenticator set pgrst.db_schemas = 'test'; + alter role "Postgrest_Test_Authenticator" set pgrst.db_schemas = 'test'; end $_$ volatile security definer language plpgsql; create function reset_db_schemas_config() returns void as $_$ begin - alter role postgrest_test_authenticator reset pgrst.db_schemas; + alter role "Postgrest_Test_Authenticator" reset pgrst.db_schemas; end $_$ volatile security definer language plpgsql ; create function test.get_current_schema() returns text as $$ diff --git a/test/load/fixtures.sql b/test/load/fixtures.sql index 3622dcf78..75bd6a8bb 100644 --- a/test/load/fixtures.sql +++ b/test/load/fixtures.sql @@ -1,7 +1,7 @@ CREATE ROLE postgrest_test_anonymous; CREATE ROLE postgrest_test_author; -GRANT postgrest_test_anonymous TO :PGUSER; -GRANT postgrest_test_author TO :PGUSER; +GRANT postgrest_test_anonymous TO :"PGUSER"; +GRANT postgrest_test_author TO :"PGUSER"; CREATE SCHEMA test; -- PUT+PATCH target needs one record and column to modify diff --git a/test/observability/fixtures/roles.sql b/test/observability/fixtures/roles.sql index e0a938b60..ef6f444ee 100644 --- a/test/observability/fixtures/roles.sql +++ b/test/observability/fixtures/roles.sql @@ -2,4 +2,4 @@ DROP ROLE IF EXISTS postgrest_test_anonymous, postgrest_test_author; CREATE ROLE postgrest_test_anonymous; CREATE ROLE postgrest_test_author; -GRANT postgrest_test_anonymous, postgrest_test_author TO :PGUSER; +GRANT postgrest_test_anonymous, postgrest_test_author TO :"PGUSER"; diff --git a/test/spec/fixtures/roles.sql b/test/spec/fixtures/roles.sql index 3590c6edb..f1b7e1ca7 100644 --- a/test/spec/fixtures/roles.sql +++ b/test/spec/fixtures/roles.sql @@ -4,4 +4,4 @@ CREATE ROLE postgrest_test_default_role; CREATE ROLE postgrest_test_author; CREATE ROLE postgrest_test_superuser WITH SUPERUSER; -GRANT postgrest_test_anonymous, postgrest_test_default_role, postgrest_test_author, postgrest_test_superuser TO :PGUSER; +GRANT postgrest_test_anonymous, postgrest_test_default_role, postgrest_test_author, postgrest_test_superuser TO :"PGUSER";