break:remove the db-use-legacy-gucs config

BREAKING CHANGE

All PostgreSQL versions will use JSON GUCs for headers, cookies and JWT claims.
This commit is contained in:
Laurence Isla
2023-11-02 15:50:22 -05:00
parent b235227119
commit 226400a5bc
22 changed files with 37 additions and 213 deletions
-1
View File
@@ -17,7 +17,6 @@ db-config = true
db-pre-config = ""
db-tx-end = "commit"
db-uri = "postgresql://"
db-use-legacy-gucs = true
jwt-aud = ""
jwt-role-claim-key = ".\"aliased\""
jwt-secret = ""
@@ -17,7 +17,6 @@ db-config = true
db-pre-config = ""
db-tx-end = "commit"
db-uri = "postgresql://"
db-use-legacy-gucs = true
jwt-aud = ""
jwt-role-claim-key = ".\"role\""
jwt-secret = ""
@@ -17,7 +17,6 @@ db-config = true
db-pre-config = ""
db-tx-end = "commit"
db-uri = "postgresql://"
db-use-legacy-gucs = true
jwt-aud = ""
jwt-role-claim-key = ".\"role\""
jwt-secret = ""
-1
View File
@@ -17,7 +17,6 @@ db-config = false
db-pre-config = ""
db-tx-end = "commit"
db-uri = "postgresql://"
db-use-legacy-gucs = true
jwt-aud = ""
jwt-role-claim-key = ".\"role\""
jwt-secret = ""
@@ -17,7 +17,6 @@ db-config = true
db-pre-config = "postgrest.pre_config"
db-tx-end = "rollback-allow-override"
db-uri = "postgresql://"
db-use-legacy-gucs = false
jwt-aud = "https://otherexample.org"
jwt-role-claim-key = ".\"other\".\"pre_config_role\""
jwt-secret = "ODERREALLYREALLYREALLYREALLYVERYSAFE"
@@ -17,7 +17,6 @@ db-config = true
db-pre-config = "postgrest.preconf"
db-tx-end = "commit-allow-override"
db-uri = "postgresql://"
db-use-legacy-gucs = false
jwt-aud = "https://example.org"
jwt-role-claim-key = ".\"a\".\"role\""
jwt-secret = "OVERRIDE=REALLY=REALLY=REALLY=REALLY=VERY=SAFE"
@@ -17,7 +17,6 @@ db-config = false
db-pre-config = "postgrest.pre_config"
db-tx-end = "rollback-allow-override"
db-uri = "tmp_db"
db-use-legacy-gucs = false
jwt-aud = "https://postgrest.org"
jwt-role-claim-key = ".\"user\"[0].\"real-role\""
jwt-secret = "c2VjdXJpdHl0aHJvdWdob2JzY3VyaXR5"
-1
View File
@@ -17,7 +17,6 @@ db-config = true
db-pre-config = ""
db-tx-end = "commit"
db-uri = "postgresql://"
db-use-legacy-gucs = true
jwt-aud = ""
jwt-role-claim-key = ".\"role\""
jwt-secret = ""
-1
View File
@@ -17,7 +17,6 @@ db-config = false
db-pre-config = "postgrest.pre_config"
db-tx-end = "rollback-allow-override"
db-uri = "tmp_db"
db-use-legacy-gucs = false
jwt-aud = "https://postgrest.org"
jwt-role-claim-key = ".user[0].\"real-role\""
jwt-secret = "c2VjdXJpdHl0aHJvdWdob2JzY3VyaXR5"
-68
View File
@@ -1,68 +0,0 @@
module Feature.LegacyGucsSpec where
import Network.Wai (Application)
import Network.HTTP.Types
import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai
import Test.Hspec.Wai.JSON
import Protolude hiding (get)
import SpecHelper
spec :: SpecWith ((), Application)
spec =
describe "remote procedure call with legacy gucs disabled" $ do
it "custom header is set" $
request methodPost "/rpc/get_guc_value" [("Custom-Header", "test")]
[json| { "prefix": "request.headers", "name": "custom-header" } |]
`shouldRespondWith`
[json|"test"|]
{ matchStatus = 200
, matchHeaders = [ matchContentTypeJson ]
}
it "standard header is set" $
request methodPost "/rpc/get_guc_value" [("Origin", "http://example.com")]
[json| { "prefix": "request.headers", "name": "origin" } |]
`shouldRespondWith`
[json|"http://example.com"|]
{ matchStatus = 200
, matchHeaders = [ matchContentTypeJson ]
}
it "current role is available as GUC claim" $
request methodPost "/rpc/get_guc_value" []
[json| { "prefix": "request.jwt.claims", "name": "role" } |]
`shouldRespondWith`
[json|"postgrest_test_anonymous"|]
{ matchStatus = 200
, matchHeaders = [ matchContentTypeJson ]
}
it "single cookie ends up as claims" $
request methodPost "/rpc/get_guc_value" [("Cookie","acookie=cookievalue")]
[json| {"prefix": "request.cookies", "name":"acookie"} |]
`shouldRespondWith`
[json|"cookievalue"|]
{ matchStatus = 200
, matchHeaders = []
}
it "multiple cookies ends up as claims" $
request methodPost "/rpc/get_guc_value" [("Cookie","acookie=cookievalue;secondcookie=anothervalue")]
[json| {"prefix": "request.cookies", "name":"secondcookie"} |]
`shouldRespondWith`
[json|"anothervalue"|]
{ matchStatus = 200
, matchHeaders = []
}
it "gets the Authorization value" $
request methodPost "/rpc/get_guc_value" [authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"]
[json| {"prefix": "request.headers", "name":"authorization"} |]
`shouldRespondWith`
[json|"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"|]
{ matchStatus = 200
, matchHeaders = []
}
+5 -36
View File
@@ -13,8 +13,7 @@ import Text.Heredoc
import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
pgVersion109, pgVersion110,
pgVersion112, pgVersion114,
pgVersion140)
pgVersion112, pgVersion114)
import Protolude hiding (get)
import SpecHelper
@@ -974,12 +973,7 @@ spec actualPgVersion =
it "custom header is set" $
request methodPost "/rpc/get_guc_value"
[("Custom-Header", "test")]
(
if actualPgVersion >= pgVersion140 then
[json| { "prefix": "request.headers", "name": "custom-header" } |]
else
[json| { "name": "request.header.custom-header" } |]
)
[json| { "prefix": "request.headers", "name": "custom-header" } |]
`shouldRespondWith`
[json|"test"|]
{ matchStatus = 200
@@ -988,12 +982,7 @@ spec actualPgVersion =
it "standard header is set" $
request methodPost "/rpc/get_guc_value"
[("Origin", "http://example.com")]
(
if actualPgVersion >= pgVersion140 then
[json| { "prefix": "request.headers", "name": "origin" } |]
else
[json| { "name": "request.header.origin" } |]
)
[json| { "prefix": "request.headers", "name": "origin" } |]
`shouldRespondWith`
[json|"http://example.com"|]
{ matchStatus = 200
@@ -1001,12 +990,7 @@ spec actualPgVersion =
}
it "current role is available as GUC claim" $
request methodPost "/rpc/get_guc_value" []
(
if actualPgVersion >= pgVersion140 then
[json| { "prefix": "request.jwt.claims", "name": "role" } |]
else
[json| { "name": "request.jwt.claim.role" } |]
)
[json| { "prefix": "request.jwt.claims", "name": "role" } |]
`shouldRespondWith`
[json|"postgrest_test_anonymous"|]
{ matchStatus = 200
@@ -1014,25 +998,15 @@ spec actualPgVersion =
}
it "single cookie ends up as claims" $
request methodPost "/rpc/get_guc_value" [("Cookie","acookie=cookievalue")]
(
if actualPgVersion >= pgVersion140 then
[json| {"prefix": "request.cookies", "name":"acookie"} |]
else
[json| {"name":"request.cookie.acookie"} |]
)
`shouldRespondWith`
[json|"cookievalue"|]
{ matchStatus = 200
, matchHeaders = []
}
it "multiple cookies ends up as claims" $
it "multiple cookies end up as claims" $
request methodPost "/rpc/get_guc_value" [("Cookie","acookie=cookievalue;secondcookie=anothervalue")]
(
if actualPgVersion >= pgVersion140 then
[json| {"prefix": "request.cookies", "name":"secondcookie"} |]
else
[json| {"name":"request.cookie.secondcookie"} |]
)
`shouldRespondWith`
[json|"anothervalue"|]
{ matchStatus = 200
@@ -1048,12 +1022,7 @@ spec actualPgVersion =
}
it "gets the Authorization value" $
request methodPost "/rpc/get_guc_value" [authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"]
(
if actualPgVersion >= pgVersion140 then
[json| {"prefix": "request.headers", "name":"authorization"} |]
else
[json| {"name":"request.header.authorization"} |]
)
`shouldRespondWith`
[json|"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"|]
{ matchStatus = 200
-6
View File
@@ -25,7 +25,6 @@ import qualified Feature.Auth.NoJwtSpec
import qualified Feature.ConcurrentSpec
import qualified Feature.CorsSpec
import qualified Feature.ExtraSearchPathSpec
import qualified Feature.LegacyGucsSpec
import qualified Feature.NoSuperuserSpec
import qualified Feature.ObservabilitySpec
import qualified Feature.OpenApi.DisabledOpenApiSpec
@@ -106,7 +105,6 @@ main = do
responseHeadersApp = app testCfgResponseHeaders
disallowRollbackApp = app testCfgDisallowRollback
forceRollbackApp = app testCfgForceRollback
testCfgLegacyGucsApp = app testCfgLegacyGucs
planEnabledApp = app testPlanEnabledCfg
pgSafeUpdateApp = app testPgSafeUpdateEnabledCfg
obsApp = app testObservabilityCfg
@@ -229,10 +227,6 @@ main = do
parallel $ before multipleSchemaApp $
describe "Feature.Query.MultipleSchemaSpec" Feature.Query.MultipleSchemaSpec.spec
-- this test runs with db-uses-legacy-gucs = false
parallel $ before testCfgLegacyGucsApp $
describe "Feature.LegacyGucsSpec" Feature.LegacyGucsSpec.spec
-- this test runs with db-plan-enabled = true
parallel $ before planEnabledApp $
describe "Feature.Query.PlanSpec.spec" $ Feature.Query.PlanSpec.spec actualPgVersion
-4
View File
@@ -116,7 +116,6 @@ baseCfg = let secret = Just $ encodeUtf8 "reallyreallyreallyreallyverysafe" in
, configDbConfig = False
, configDbPreConfig = Nothing
, configDbUri = "postgresql://"
, configDbUseLegacyGucs = True
, configFilePath = Nothing
, configJWKS = parseSecret <$> secret
, configJwtAudience = Nothing
@@ -226,9 +225,6 @@ testCfgResponseHeaders = baseCfg { configDbPreRequest = Just $ QualifiedIdentifi
testMultipleSchemaCfg :: AppConfig
testMultipleSchemaCfg = baseCfg { configDbSchemas = fromList ["v1", "v2", "SPECIAL \"@/\\#~_-"] }
testCfgLegacyGucs :: AppConfig
testCfgLegacyGucs = baseCfg { configDbUseLegacyGucs = False }
testPgSafeUpdateEnabledCfg :: AppConfig
testPgSafeUpdateEnabledCfg = baseCfg { configDbPreRequest = Just $ QualifiedIdentifier "test" "load_safeupdate" }
+14 -45
View File
@@ -91,10 +91,7 @@ CREATE FUNCTION set_authors_only_owner() RETURNS trigger
LANGUAGE plpgsql
AS $$
begin
NEW.owner = case when current_setting('server_version_num')::int >= 140000
then current_setting('request.jwt.claims')::json->>'id'
else current_setting('request.jwt.claim.id')
end;
NEW.owner = current_setting('request.jwt.claims')::json->>'id';
RETURN NEW;
end
$$;
@@ -377,10 +374,7 @@ CREATE OR REPLACE FUNCTION switch_role() RETURNS void
declare
user_id text;
Begin
user_id = case when current_setting('server_version_num')::int >= 140000
then (current_setting('request.jwt.claims')::json->>'id')::text
else current_setting('request.jwt.claim.id')::text
end;
user_id = (current_setting('request.jwt.claims')::json->>'id')::text;
if user_id = '1'::text then
execute 'set local role postgrest_test_author';
elseif user_id = '2'::text then
@@ -408,34 +402,15 @@ CREATE FUNCTION reveal_big_jwt() RETURNS TABLE (
iss text, sub text, exp bigint,
nbf bigint, iat bigint, jti text, "http://postgrest.com/foo" boolean
)
LANGUAGE plpgsql SECURITY DEFINER
STABLE
AS $$
BEGIN
-- JWT claims are set in JSON format since v14
IF (current_setting('server_version_num')::INT >= 140000) THEN
RETURN QUERY
SELECT current_setting('request.jwt.claims')::json->>'iss' as iss,
current_setting('request.jwt.claims')::json->>'sub' as sub,
(current_setting('request.jwt.claims')::json->>'exp')::bigint as exp,
(current_setting('request.jwt.claims')::json->>'nbf')::bigint as nbf,
(current_setting('request.jwt.claims')::json->>'iat')::bigint as iat,
current_setting('request.jwt.claims')::json->>'jti' as jti,
(current_setting('request.jwt.claims')::json->>'http://postgrest.com/foo')::boolean
as "http://postgrest.com/foo";
ELSE
RETURN QUERY
SELECT current_setting('request.jwt.claim.iss') as iss,
current_setting('request.jwt.claim.sub') as sub,
current_setting('request.jwt.claim.exp')::bigint as exp,
current_setting('request.jwt.claim.nbf')::bigint as nbf,
current_setting('request.jwt.claim.iat')::bigint as iat,
current_setting('request.jwt.claim.jti') as jti,
current_setting('request.jwt.claim.http://postgrest.com/foo')::boolean
as "http://postgrest.com/foo";
END IF;
END;
$$;
AS $$
SELECT current_setting('request.jwt.claims')::json->>'iss' as iss,
current_setting('request.jwt.claims')::json->>'sub' as sub,
(current_setting('request.jwt.claims')::json->>'exp')::bigint as exp,
(current_setting('request.jwt.claims')::json->>'nbf')::bigint as nbf,
(current_setting('request.jwt.claims')::json->>'iat')::bigint as iat,
current_setting('request.jwt.claims')::json->>'jti' as jti,
(current_setting('request.jwt.claims')::json->>'http://postgrest.com/foo')::boolean as "http://postgrest.com/foo";
$$ LANGUAGE sql SECURITY DEFINER STABLE;
CREATE FUNCTION assert() RETURNS void
@@ -1187,7 +1162,7 @@ create function test.get_guc_value(name text) returns text as $$
select nullif(current_setting(name), '')::text;
$$ language sql;
-- Get the GUC values for Postgres v14.0 and up
-- Get the JSON type GUC values
create function test.get_guc_value(prefix text, name text) returns text as $$
select nullif(current_setting(prefix)::json->>name, '')::text;
$$ language sql;
@@ -2093,15 +2068,9 @@ where fst_shift_activity_id is not null
-- for a pre-request function
create or replace function custom_headers() returns void as $$
declare
user_agent text := case when current_setting('server_version_num')::int >= 140000
then current_setting('request.headers', true)::json->>'user-agent'
else current_setting('request.header.user-agent', true)
end;
user_agent text := current_setting('request.headers', true)::json->>'user-agent';
req_path text := current_setting('request.path', true);
req_accept text := case when current_setting('server_version_num')::int >= 140000
then current_setting('request.headers', true)::json->>'accept'
else current_setting('request.header.accept', true)
end;
req_accept text := current_setting('request.headers', true)::json->>'accept';
req_method text := current_setting('request.method', true);
begin
if user_agent similar to 'MSIE (6.0|7.0)' then