diff --git a/src/PostgREST/Middleware.hs b/src/PostgREST/Middleware.hs index 34533b23e..9232cb88e 100644 --- a/src/PostgREST/Middleware.hs +++ b/src/PostgREST/Middleware.hs @@ -33,12 +33,12 @@ runWithClaims conf eClaims app req = JWTClaims claims -> do -- role claim defaults to anon if not specified in jwt let setClaims = claimsToSQL (M.union claims (M.singleton "role" anon)) - H.sql (mconcat $ setClaims ++ customReqCheck) + H.sql $ mconcat setClaims + mapM_ H.sql customReqCheck app req where anon = String . toS $ configAnonRole conf - customReqCheck = maybeToList $ (\f -> "select " <> toS f <> "();") - <$> configReqCheck conf + customReqCheck = (\f -> "select " <> toS f <> "();") <$> configReqCheck conf unauthed message = responseLBS unauthorized401 [ ctToHeader CTApplicationJSON , ( "WWW-Authenticate" diff --git a/test/Feature/AuthSpec.hs b/test/Feature/AuthSpec.hs index ceb2b0378..bda4931a4 100644 --- a/test/Feature/AuthSpec.hs +++ b/test/Feature/AuthSpec.hs @@ -1,6 +1,7 @@ module Feature.AuthSpec where -- {{{ Imports +import Text.Heredoc import Test.Hspec import Test.Hspec.Wai import Test.Hspec.Wai.JSON @@ -103,11 +104,6 @@ spec = describe "authorization" $ do ] } - it "runs a custom request validation proc" $ do - let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYmFkX3JvbGUifQ.ENAiheEOlskpfoT5byj-gKJkOhHKTvETQu1Zso3c4Ts" - request methodGet "/items" [auth] "" - `shouldRespondWith` 400 - it "should fail when jwt contains no claims" $ do let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.lu-rG8aSCiw-aOlN0IxpRGz5r7Jwq7K9r3tuMPUpytI" request methodGet "/authors_only" [auth] "" @@ -124,3 +120,35 @@ spec = describe "authorization" $ do _ <- request methodPost "/rpc/problem" [auth] "" request methodGet "/authors_only" [auth] "" `shouldRespondWith` 200 + + describe "custom pre-request proc acting on id claim" $ do + + it "able to switch to postgrest_test_author role (id=1)" $ + let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MX0.mI2HNoOum6xM3sc4oHLxU4yLv-_WV5W1kqBfY_wEvLw" in + request methodPost "/rpc/get_current_user" [auth] + [json| {} |] + `shouldRespondWith` ResponseMatcher { + matchBody = Just [str|"postgrest_test_author"|] + , matchStatus = 200 + , matchHeaders = [] + } + + it "able to switch to postgrest_test_default_role (id=2)" $ + let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Mn0.W7jLsG-zswM91AJkCvZeIMHrnz7_6ceY2jnscVl3Yhk" in + request methodPost "/rpc/get_current_user" [auth] + [json| {} |] + `shouldRespondWith` ResponseMatcher { + matchBody = Just [str|"postgrest_test_default_role"|] + , matchStatus = 200 + , matchHeaders = [] + } + + it "raises error (id=3)" $ + let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6M30.15Gy8PezQhJIaHYDJVLa-Gmz9T3sJnW66EKAYIsXc7c" in + request methodPost "/rpc/get_current_user" [auth] + [json| {} |] + `shouldRespondWith` ResponseMatcher { + matchBody = Just [str|{"hint":"Please contact administrator","details":null,"code":"P0001","message":"Disabled ID --> 3"}|] + , matchStatus = 400 + , matchHeaders = [] + } diff --git a/test/SpecHelper.hs b/test/SpecHelper.hs index b07ffe225..97675dbc8 100644 --- a/test/SpecHelper.hs +++ b/test/SpecHelper.hs @@ -51,7 +51,7 @@ testDbConn = "postgres://postgrest_test_authenticator@localhost:5432/postgrest_t testCfg :: AppConfig testCfg = - AppConfig testDbConn "postgrest_test_anonymous" Nothing "test" "localhost" 3000 (Just "safe") 10 Nothing (Just "test.block_bad_role") True + AppConfig testDbConn "postgrest_test_anonymous" Nothing "test" "localhost" 3000 (Just "safe") 10 Nothing (Just "test.switch_role") True testCfgNoJWT :: AppConfig testCfgNoJWT = diff --git a/test/fixtures/database.sql b/test/fixtures/database.sql index c80120bd8..a31b4aa2b 100644 --- a/test/fixtures/database.sql +++ b/test/fixtures/database.sql @@ -2,3 +2,5 @@ DROP DATABASE IF EXISTS postgrest_test; DROP ROLE IF EXISTS postgrest_test; CREATE USER postgrest_test createdb createrole; CREATE DATABASE postgrest_test OWNER postgrest_test; + +ALTER DATABASE postgrest_test SET postgrest.claims.id = '-1'; diff --git a/test/fixtures/privileges.sql b/test/fixtures/privileges.sql index fa590df9f..3a94812af 100644 --- a/test/fixtures/privileges.sql +++ b/test/fixtures/privileges.sql @@ -4,7 +4,7 @@ GRANT USAGE ON SCHEMA , test , jwt , "تست" -TO postgrest_test_anonymous, bad_role; +TO postgrest_test_anonymous; -- Schema test objects SET search_path = test, "تست", pg_catalog; diff --git a/test/fixtures/roles.sql b/test/fixtures/roles.sql index aa507c87d..a146a8fc8 100644 --- a/test/fixtures/roles.sql +++ b/test/fixtures/roles.sql @@ -1,8 +1,7 @@ -DROP ROLE IF EXISTS postgrest_test_authenticator, postgrest_test_anonymous, postgrest_test_default_role, postgrest_test_author, bad_role; +DROP ROLE IF EXISTS postgrest_test_authenticator, postgrest_test_anonymous, postgrest_test_default_role, postgrest_test_author; CREATE ROLE postgrest_test_authenticator WITH login noinherit; CREATE ROLE postgrest_test_anonymous; CREATE ROLE postgrest_test_default_role; CREATE ROLE postgrest_test_author; -CREATE ROLE bad_role; -GRANT postgrest_test_anonymous, postgrest_test_default_role, postgrest_test_author, bad_role TO postgrest_test_authenticator; +GRANT postgrest_test_anonymous, postgrest_test_default_role, postgrest_test_author TO postgrest_test_authenticator; diff --git a/test/fixtures/schema.sql b/test/fixtures/schema.sql index 56d8f6d8e..96e0c2b6f 100755 --- a/test/fixtures/schema.sql +++ b/test/fixtures/schema.sql @@ -237,15 +237,32 @@ SELECT jwt.sign( ) r; $$; -create function block_bad_role() returns void -language plpgsql as $$ + +CREATE OR REPLACE FUNCTION switch_role() RETURNS void + LANGUAGE plpgsql + AS $$ +declare + user_id text; begin - if current_role = 'bad_role' then - raise invalid_password using message = 'role is not allowed'; + user_id = current_setting('postgrest.claims.id')::text; + if user_id = '1'::text then + execute 'set local role postgrest_test_author'; + elseif user_id = '2'::text then + execute 'set local role postgrest_test_default_role'; + elseif user_id = '3'::text then + RAISE EXCEPTION 'Disabled ID --> %', user_id USING HINT = 'Please contact administrator'; + /* else */ + /* execute 'set local role postgrest_test_anonymous'; */ end if; end $$; +CREATE FUNCTION get_current_user() RETURNS text + LANGUAGE sql + AS $$ +SELECT current_user::text; +$$; + -- -- Name: reveal_big_jwt(); Type: FUNCTION; Schema: test; Owner: - --