feat: Make db-anon-role optional

Without db-anon-role, PostgREST will block any anonymous access without hitting the database.

Resolves #1689, Ref #1823
This commit is contained in:
Wolfgang Walther
2022-01-22 15:59:26 +01:00
parent 05b5ecd23b
commit c3ade07ad6
27 changed files with 90 additions and 50 deletions
-2
View File
@@ -1,5 +1,3 @@
db-anon-role = "required"
db-schema = "provided_through_alias"
max-rows = 1000
pre-request = "check_alias"
-2
View File
@@ -1,5 +1,3 @@
db-anon-role = "required"
db-channel-enabled = "1"
db-prepared-statements = "0"
jwt-secret-is-base64 = "2"
-2
View File
@@ -1,5 +1,3 @@
db-anon-role = "required"
db-channel-enabled = "true"
db-prepared-statements = "FALSE"
jwt-secret-is-base64 = "\"true\""
-1
View File
@@ -1,3 +1,2 @@
db-anon-role = "required"
# Not the default, but only works with PG* variables, which are not set
db-config = false
+1 -1
View File
@@ -1,4 +1,4 @@
db-anon-role = "required"
db-anon-role = ""
db-channel = "pgrst"
db-channel-enabled = true
db-extra-search-path = "public"
@@ -1,4 +1,4 @@
db-anon-role = "required"
db-anon-role = ""
db-channel = "pgrst"
db-channel-enabled = true
db-extra-search-path = "public"
@@ -1,4 +1,4 @@
db-anon-role = "required"
db-anon-role = ""
db-channel = "pgrst"
db-channel-enabled = true
db-extra-search-path = "public"
+1 -1
View File
@@ -1,4 +1,4 @@
db-anon-role = "required"
db-anon-role = ""
db-channel = "pgrst"
db-channel-enabled = true
db-extra-search-path = "public"
@@ -1,4 +1,4 @@
db-anon-role = "postgrest_test_anonymous"
db-anon-role = "other"
db-channel = "postgrest"
db-channel-enabled = false
db-extra-search-path = "public,extensions,other"
@@ -1,4 +1,4 @@
db-anon-role = "postgrest_test_anonymous"
db-anon-role = "anonymous"
db-channel = "postgrest"
db-channel-enabled = false
db-extra-search-path = "public,extensions,private"
+1 -1
View File
@@ -1,4 +1,4 @@
db-anon-role = "required"
db-anon-role = ""
db-channel = "pgrst"
db-channel-enabled = true
db-extra-search-path = "public"
-1
View File
@@ -1,5 +1,4 @@
# tests how config options fall back with invalid types
db-anon-role = "required"
# expects string
app.settings.test = false
+2 -1
View File
@@ -7,6 +7,7 @@ ALTER ROLE db_config_authenticator SET pgrst.raw_media_types = 'application/vnd.
ALTER ROLE db_config_authenticator SET pgrst.jwt_secret = 'REALLY=REALLY=REALLY=REALLY=VERY=SAFE';
ALTER ROLE db_config_authenticator SET pgrst.jwt_secret_is_base64 = 'false';
ALTER ROLE db_config_authenticator SET pgrst.jwt_role_claim_key = '."a"."role"';
ALTER ROLE db_config_authenticator SET pgrst.db_anon_role = 'anonymous';
ALTER ROLE db_config_authenticator SET pgrst.db_tx_end = 'commit-allow-override';
ALTER ROLE db_config_authenticator SET pgrst.db_schemas = 'test, tenant1, tenant2';
ALTER ROLE db_config_authenticator SET pgrst.db_root_spec = 'root';
@@ -29,7 +30,6 @@ ALTER ROLE db_config_authenticator SET pgrst.server_port = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.server_unix_socket = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.server_unix_socket_mode = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.log_level = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_anon_role = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_uri = 'postgresql://ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_channel_enabled = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_channel = 'ignored';
@@ -45,6 +45,7 @@ ALTER ROLE other_authenticator SET pgrst.raw_media_types = 'application/vnd.pgrs
ALTER ROLE other_authenticator SET pgrst.jwt_secret = 'ODERREALLYREALLYREALLYREALLYVERYSAFE';
ALTER ROLE other_authenticator SET pgrst.jwt_secret_is_base64 = 'true';
ALTER ROLE other_authenticator SET pgrst.jwt_role_claim_key = '."other"."role"';
ALTER ROLE other_authenticator SET pgrst.db_anon_role = 'other';
ALTER ROLE other_authenticator SET pgrst.db_tx_end = 'rollback-allow-override';
ALTER ROLE other_authenticator SET pgrst.db_schemas = 'test, other_tenant1, other_tenant2';
ALTER ROLE other_authenticator SET pgrst.db_root_spec = 'other_root';
+2
View File
@@ -1,6 +1,8 @@
\ir db_config.sql
CREATE ROLE postgrest_test_anonymous;
ALTER ROLE :USER SET pgrst.db_anon_role = 'postgrest_test_anonymous';
CREATE ROLE postgrest_test_author;
GRANT postgrest_test_anonymous, postgrest_test_author TO :USER;
-4
View File
@@ -23,10 +23,6 @@ cli:
- name: invalid config file
expect: error
args: ['test/io-tests/configs/invalid.yaml']
# failures: required config options
- name: missing db-anon-role
expect: error
env:
# failures: wrong config values
- name: invalid server-unix-socket-mode not octal
expect: error
+7 -4
View File
@@ -92,8 +92,7 @@ def defaultenv():
"PGDATABASE": os.environ["PGDATABASE"],
"PGHOST": os.environ["PGHOST"],
"PGUSER": os.environ["PGUSER"],
"PGRST_DB_ANON_ROLE": os.environ["PGRST_DB_ANON_ROLE"],
"PGRST_DB_CONFIG": "false",
"PGRST_DB_CONFIG": "true",
"PGRST_LOG_LEVEL": "info",
}
@@ -384,6 +383,7 @@ def test_read_secret_from_file(secretpath, defaultenv):
with run(stdin=secret, env=env) as postgrest:
response = postgrest.session.get("/authors_only", headers=headers)
print(response.text)
assert response.status_code == 200
@@ -600,6 +600,8 @@ def test_jwt_secret_external_file_reload(tmp_path, defaultenv):
**defaultenv,
"PGRST_JWT_SECRET": f"@{external_secret_file}",
"PGRST_DB_CHANNEL_ENABLED": "true",
"PGRST_DB_CONFIG": "false",
"PGRST_DB_ANON_ROLE": "postgrest_test_anonymous", # required for NOTIFY
}
with run(env=env) as postgrest:
@@ -609,7 +611,7 @@ def test_jwt_secret_external_file_reload(tmp_path, defaultenv):
# change external file
external_secret_file.write_text(SECRET)
# SIGUSR1 doesn't reload external files
# SIGUSR1 doesn't reload external files, at least when db-config=false
postgrest.process.send_signal(signal.SIGUSR1)
time.sleep(0.1)
@@ -627,7 +629,8 @@ def test_jwt_secret_external_file_reload(tmp_path, defaultenv):
external_secret_file.write_text("invalid" * 5)
# reload config and external file with NOTIFY
postgrest.session.post("/rpc/reload_pgrst_config")
response = postgrest.session.post("/rpc/reload_pgrst_config")
assert response.status_code == 200
time.sleep(0.1)
response = postgrest.session.get("/authors_only", headers=headers)
+30
View File
@@ -0,0 +1,30 @@
module Feature.NoAnonSpec where
import Network.Wai (Application)
import Network.HTTP.Types
import Test.Hspec
import Test.Hspec.Wai
import Test.Hspec.Wai.JSON
import Protolude hiding (get)
import SpecHelper
spec :: SpecWith ((), Application)
spec = describe "server started without anonymous role" $ do
it "behaves normally on attempted auth" $ do
-- token body: { "role": "postgrest_test_author" }
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"
request methodGet "/authors_only"
[auth]
""
`shouldRespondWith`
200
it "responds with error when user does not attempt auth" $
get "/items"
`shouldRespondWith`
[json|{"message":"Anonymous access is disabled"}|]
{ matchStatus = 401
, matchHeaders = ["WWW-Authenticate" <:> "Bearer"]
}
+6
View File
@@ -37,6 +37,7 @@ import qualified Feature.InsertSpec
import qualified Feature.JsonOperatorSpec
import qualified Feature.LegacyGucsSpec
import qualified Feature.MultipleSchemaSpec
import qualified Feature.NoAnonSpec
import qualified Feature.NoJwtSpec
import qualified Feature.NonexistentSchemaSpec
import qualified Feature.OpenApiSpec
@@ -96,6 +97,7 @@ main = do
maxRowsApp = app testMaxRowsCfg
disabledOpenApi = app testDisabledOpenApiCfg
proxyApp = app testProxyCfg
noAnonApp = app testCfgNoAnon
noJwtApp = app testCfgNoJWT
binaryJwtApp = app testCfgBinaryJWT
audJwtApp = app testCfgAudienceJWT
@@ -170,6 +172,10 @@ main = do
parallel $ before proxyApp $
describe "Feature.ProxySpec" Feature.ProxySpec.spec
-- this test runs without an anonymous role
parallel $ before noAnonApp $
describe "Feature.NoAnonSpec" Feature.NoAnonSpec.spec
-- this test runs without a JWT secret
parallel $ before noJwtApp $
describe "Feature.NoJwtSpec" Feature.NoJwtSpec.spec
+4 -1
View File
@@ -76,7 +76,7 @@ baseCfg :: AppConfig
baseCfg = let secret = Just $ encodeUtf8 "reallyreallyreallyreallyverysafe" in
AppConfig {
configAppSettings = [ ("app.settings.app_host", "localhost") , ("app.settings.external_api_secret", "0123456789abcdef") ]
, configDbAnonRole = "postgrest_test_anonymous"
, configDbAnonRole = Just "postgrest_test_anonymous"
, configDbChannel = mempty
, configDbChannelEnabled = True
, configDbExtraSearchPath = []
@@ -118,6 +118,9 @@ testCfgDisallowRollback = baseCfg { configDbTxAllowOverride = False, configDbTxR
testCfgForceRollback :: AppConfig
testCfgForceRollback = baseCfg { configDbTxAllowOverride = False, configDbTxRollbackAll = True }
testCfgNoAnon :: AppConfig
testCfgNoAnon = baseCfg { configDbAnonRole = Nothing }
testCfgNoJWT :: AppConfig
testCfgNoJWT = baseCfg { configJwtSecret = Nothing, configJWKS = Nothing }