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:
@@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Removed [raw-media-types config](https://postgrest.org/en/v11.1/references/configuration.html#raw-media-types) - @steve-chavez
|
||||
- Removed `application/octet-stream`, `text/plain`, `text/xml` [builtin support for scalar results](https://postgrest.org/en/v11.1/references/api/resource_representation.html#scalar-function-response-format) - @steve-chavez
|
||||
- Removed default `application/openapi+json` media type for [db-root-spec](https://postgrest.org/en/v11.1/references/configuration.html#db-root-spec) - @steve-chavez
|
||||
- Removed [db-use-legacy-gucs](https://postgrest.org/en/v11.2/references/configuration.html#db-use-legacy-gucs) - @laurenceisla
|
||||
|
||||
## [11.2.2] - 2023-10-25
|
||||
|
||||
|
||||
@@ -192,7 +192,6 @@ test-suite spec
|
||||
Feature.ConcurrentSpec
|
||||
Feature.CorsSpec
|
||||
Feature.ExtraSearchPathSpec
|
||||
Feature.LegacyGucsSpec
|
||||
Feature.NoSuperuserSpec
|
||||
Feature.ObservabilitySpec
|
||||
Feature.OpenApi.DisabledOpenApiSpec
|
||||
|
||||
@@ -251,7 +251,7 @@ handleRequest AuthResult{..} conf appState authenticated prepared pgVer apiReq@A
|
||||
roleIsoLvl = HM.findWithDefault SQL.ReadCommitted authRole $ configRoleIsoLvl conf
|
||||
runQuery isoLvl mode query =
|
||||
runDbHandler appState isoLvl mode authenticated prepared $ do
|
||||
Query.setPgLocals conf authClaims authRole (HM.toList roleSettings) apiReq pgVer
|
||||
Query.setPgLocals conf authClaims authRole (HM.toList roleSettings) apiReq
|
||||
Query.runPreReq conf
|
||||
query
|
||||
|
||||
|
||||
@@ -191,10 +191,6 @@ exampleConfigFile =
|
||||
|## https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING
|
||||
|db-uri = "postgresql://"
|
||||
|
|
||||
|## Determine if GUC request settings for headers, cookies and jwt claims use the legacy names (string with dashes, invalid starting from PostgreSQL v14) with text values instead of the new names (string without dashes, valid on all PostgreSQL versions) with json values.
|
||||
|## For PostgreSQL v14 and up, this setting will be ignored.
|
||||
|db-use-legacy-gucs = true
|
||||
|
|
||||
|# jwt-aud = "your_audience_claim"
|
||||
|
|
||||
|## Jspath to the role claim key
|
||||
|
||||
@@ -89,7 +89,6 @@ data AppConfig = AppConfig
|
||||
, configDbTxAllowOverride :: Bool
|
||||
, configDbTxRollbackAll :: Bool
|
||||
, configDbUri :: Text
|
||||
, configDbUseLegacyGucs :: Bool
|
||||
, configFilePath :: Maybe FilePath
|
||||
, configJWKS :: Maybe JWKSet
|
||||
, configJwtAudience :: Maybe StringOrURI
|
||||
@@ -157,7 +156,6 @@ toText conf =
|
||||
,("db-pre-config", q . maybe mempty dumpQi . configDbPreConfig)
|
||||
,("db-tx-end", q . showTxEnd)
|
||||
,("db-uri", q . configDbUri)
|
||||
,("db-use-legacy-gucs", T.toLower . show . configDbUseLegacyGucs)
|
||||
,("jwt-aud", T.decodeUtf8 . LBS.toStrict . JSON.encode . maybe "" toJSON . configJwtAudience)
|
||||
,("jwt-role-claim-key", q . T.intercalate mempty . fmap dumpJSPath . configJwtRoleClaimKey)
|
||||
,("jwt-secret", q . T.decodeUtf8 . showJwtSecret)
|
||||
@@ -257,7 +255,6 @@ parser optPath env dbSettings roleSettings roleIsolationLvl =
|
||||
<*> parseTxEnd "db-tx-end" snd
|
||||
<*> parseTxEnd "db-tx-end" fst
|
||||
<*> (fromMaybe "postgresql://" <$> optString "db-uri")
|
||||
<*> (fromMaybe True <$> optBool "db-use-legacy-gucs")
|
||||
<*> pure optPath
|
||||
<*> pure Nothing
|
||||
<*> parseJwtAudience "jwt-aud"
|
||||
|
||||
@@ -53,7 +53,6 @@ dbSettingsNames =
|
||||
,"db_root_spec"
|
||||
,"db_schemas"
|
||||
,"db_tx_end"
|
||||
,"db_use_legacy_gucs"
|
||||
,"jwt_aud"
|
||||
,"jwt_role_claim_key"
|
||||
,"jwt_secret"
|
||||
|
||||
+12
-31
@@ -14,13 +14,11 @@ module PostgREST.Query
|
||||
) where
|
||||
|
||||
import qualified Data.Aeson as JSON
|
||||
import qualified Data.Aeson.Key as K
|
||||
import qualified Data.Aeson.KeyMap as KM
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Lazy.Char8 as LBS
|
||||
import qualified Data.HashMap.Strict as HM
|
||||
import qualified Data.Set as S
|
||||
import qualified Data.Text.Encoding as T
|
||||
import qualified Hasql.Decoders as HD
|
||||
import qualified Hasql.DynamicStatements.Snippet as SQL (Snippet)
|
||||
import qualified Hasql.DynamicStatements.Statement as SQL
|
||||
@@ -33,8 +31,6 @@ import qualified PostgREST.Query.Statements as Statements
|
||||
import qualified PostgREST.RangeQuery as RangeQuery
|
||||
import qualified PostgREST.SchemaCache as SchemaCache
|
||||
|
||||
import Data.Scientific (FPFormat (..), formatScientific, isInteger)
|
||||
|
||||
import PostgREST.ApiRequest (ApiRequest (..))
|
||||
import PostgREST.ApiRequest.Preferences (PreferCount (..),
|
||||
PreferTransaction (..),
|
||||
@@ -42,8 +38,7 @@ import PostgREST.ApiRequest.Preferences (PreferCount (..),
|
||||
shouldCount)
|
||||
import PostgREST.Config (AppConfig (..),
|
||||
OpenAPIMode (..))
|
||||
import PostgREST.Config.PgVersion (PgVersion (..),
|
||||
pgVersion140)
|
||||
import PostgREST.Config.PgVersion (PgVersion (..))
|
||||
import PostgREST.Error (Error)
|
||||
import PostgREST.MediaType (MediaType (..))
|
||||
import PostgREST.Plan (CallReadPlan (..),
|
||||
@@ -238,37 +233,23 @@ optionalRollback AppConfig{..} ApiRequest{iPreferences=Preferences{..}} = do
|
||||
|
||||
-- | Runs local (transaction scoped) GUCs for every request.
|
||||
setPgLocals :: AppConfig -> KM.KeyMap JSON.Value -> BS.ByteString -> [(ByteString, ByteString)] ->
|
||||
ApiRequest -> PgVersion -> DbHandler ()
|
||||
setPgLocals AppConfig{..} claims role roleSettings req actualPgVersion = lift $
|
||||
ApiRequest -> DbHandler ()
|
||||
setPgLocals AppConfig{..} claims role roleSettings req = lift $
|
||||
SQL.statement mempty $ SQL.dynamicallyParameterized
|
||||
("select " <> intercalateSnippet ", " (searchPathSql : roleSql ++ roleSettingsSql ++ claimsSql ++ [methodSql, pathSql] ++ headersSql ++ cookiesSql ++ appSettingsSql))
|
||||
HD.noResult configDbPreparedStatements
|
||||
where
|
||||
methodSql = setConfigLocal mempty ("request.method", iMethod req)
|
||||
pathSql = setConfigLocal mempty ("request.path", iPath req)
|
||||
headersSql = if usesLegacyGucs
|
||||
then setConfigLocal "request.header." <$> iHeaders req
|
||||
else setConfigLocalJson "request.headers" (iHeaders req)
|
||||
cookiesSql = if usesLegacyGucs
|
||||
then setConfigLocal "request.cookie." <$> iCookies req
|
||||
else setConfigLocalJson "request.cookies" (iCookies req)
|
||||
claimsSql = if usesLegacyGucs
|
||||
then setConfigLocal "request.jwt.claim." <$> [(toUtf8 $ K.toText c, toUtf8 $ unquoted v) | (c,v) <- KM.toList claims]
|
||||
else [setConfigLocal mempty ("request.jwt.claims", LBS.toStrict $ JSON.encode claims)]
|
||||
roleSql = [setConfigLocal mempty ("role", role)]
|
||||
roleSettingsSql = setConfigLocal mempty <$> roleSettings
|
||||
appSettingsSql = setConfigLocal mempty <$> (join bimap toUtf8 <$> configAppSettings)
|
||||
methodSql = setConfigLocal ("request.method", iMethod req)
|
||||
pathSql = setConfigLocal ("request.path", iPath req)
|
||||
headersSql = setConfigLocalJson "request.headers" (iHeaders req)
|
||||
cookiesSql = setConfigLocalJson "request.cookies" (iCookies req)
|
||||
claimsSql = [setConfigLocal ("request.jwt.claims", LBS.toStrict $ JSON.encode claims)]
|
||||
roleSql = [setConfigLocal ("role", role)]
|
||||
roleSettingsSql = setConfigLocal <$> roleSettings
|
||||
appSettingsSql = setConfigLocal <$> (join bimap toUtf8 <$> configAppSettings)
|
||||
searchPathSql =
|
||||
let schemas = escapeIdentList (iSchema req : configDbExtraSearchPath) in
|
||||
setConfigLocal mempty ("search_path", schemas)
|
||||
usesLegacyGucs = configDbUseLegacyGucs && actualPgVersion < pgVersion140
|
||||
|
||||
unquoted :: JSON.Value -> Text
|
||||
unquoted (JSON.String t) = t
|
||||
unquoted (JSON.Number n) =
|
||||
toS $ formatScientific Fixed (if isInteger n then Just 0 else Nothing) n
|
||||
unquoted (JSON.Bool b) = show b
|
||||
unquoted v = T.decodeUtf8 . LBS.toStrict $ JSON.encode v
|
||||
setConfigLocal ("search_path", schemas)
|
||||
|
||||
-- | Runs the pre-request function.
|
||||
runPreReq :: AppConfig -> DbHandler ()
|
||||
|
||||
@@ -484,14 +484,14 @@ explainF fmt opts snip =
|
||||
fmtPlanFmt PlanJSON = "FORMAT JSON"
|
||||
|
||||
-- | Do a pg set_config(setting, value, true) call. This is equivalent to a SET LOCAL.
|
||||
setConfigLocal :: ByteString -> (ByteString, ByteString) -> SQL.Snippet
|
||||
setConfigLocal prefix (k, v) =
|
||||
"set_config(" <> unknownEncoder (prefix <> k) <> ", " <> unknownEncoder v <> ", true)"
|
||||
setConfigLocal :: (ByteString, ByteString) -> SQL.Snippet
|
||||
setConfigLocal (k, v) =
|
||||
"set_config(" <> unknownEncoder k <> ", " <> unknownEncoder v <> ", true)"
|
||||
|
||||
-- | Starting from PostgreSQL v14, some characters are not allowed for config names (mostly affecting headers with "-").
|
||||
-- | A JSON format string is used to avoid this problem. See https://github.com/PostgREST/postgrest/issues/1857
|
||||
setConfigLocalJson :: ByteString -> [(ByteString, ByteString)] -> [SQL.Snippet]
|
||||
setConfigLocalJson prefix keyVals = [setConfigLocal mempty (prefix, gucJsonVal keyVals)]
|
||||
setConfigLocalJson prefix keyVals = [setConfigLocal (prefix, gucJsonVal keyVals)]
|
||||
where
|
||||
gucJsonVal :: [(ByteString, ByteString)] -> ByteString
|
||||
gucJsonVal = LBS.toStrict . JSON.encode . HM.fromList . arrayByteStringToText
|
||||
|
||||
@@ -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