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:
@@ -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 = ""
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 = 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,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 = []
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" }
|
||||
|
||||
|
||||
Vendored
+14
-45
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user