mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Perform RLS WITH CHECK before constraints, etc
The RLS capability is built on top of the WITH CHECK OPTION system which was added for auto-updatable views, however, unlike WCOs on views (which are mandated by the SQL spec to not fire until after all other constraints and checks are done), it makes much more sense for RLS checks to happen earlier than constraint and uniqueness checks. This patch reworks the structure which holds the WCOs a bit to be explicitly either VIEW or RLS checks and the RLS-related checks are done prior to the constraint and uniqueness checks. This also allows better error reporting as we are now reporting when a violation is due to a WITH CHECK OPTION and when it's due to an RLS policy violation, which was independently noted by Craig Ringer as being confusing. The documentation is also updated to include a paragraph about when RLS WITH CHECK handling is performed, as there have been a number of questions regarding that and the documentation was previously silent on the matter. Author: Dean Rasheed, with some kabitzing and comment changes by me.
This commit is contained in:
@ -57,7 +57,7 @@ SELECT * FROM rls_test_permissive;
|
||||
INSERT INTO rls_test_permissive VALUES ('r1','s1',10);
|
||||
-- failure
|
||||
INSERT INTO rls_test_permissive VALUES ('r4','s4',10);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_permissive"
|
||||
ERROR: new row violates row level security policy for "rls_test_permissive"
|
||||
SET ROLE s1;
|
||||
-- With only the hook's policies, restrictive
|
||||
-- hook's policy is current_user = supervisor
|
||||
@ -78,7 +78,7 @@ SELECT * FROM rls_test_restrictive;
|
||||
INSERT INTO rls_test_restrictive VALUES ('r1','s1',10);
|
||||
-- failure
|
||||
INSERT INTO rls_test_restrictive VALUES ('r4','s4',10);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_restrictive"
|
||||
ERROR: new row violates row level security policy for "rls_test_restrictive"
|
||||
SET ROLE s1;
|
||||
-- With only the hook's policies, both
|
||||
-- permissive hook's policy is current_user = username
|
||||
@ -100,13 +100,13 @@ SELECT * FROM rls_test_both;
|
||||
|
||||
-- failure
|
||||
INSERT INTO rls_test_both VALUES ('r1','s1',10);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_both"
|
||||
ERROR: new row violates row level security policy for "rls_test_both"
|
||||
-- failure
|
||||
INSERT INTO rls_test_both VALUES ('r4','s1',10);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_both"
|
||||
ERROR: new row violates row level security policy for "rls_test_both"
|
||||
-- failure
|
||||
INSERT INTO rls_test_both VALUES ('r4','s4',10);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_both"
|
||||
ERROR: new row violates row level security policy for "rls_test_both"
|
||||
RESET ROLE;
|
||||
-- Create "internal" policies, to check that the policies from
|
||||
-- the hooks are combined correctly.
|
||||
@ -136,7 +136,7 @@ INSERT INTO rls_test_permissive VALUES ('r1','s1',7);
|
||||
INSERT INTO rls_test_permissive VALUES ('r3','s3',10);
|
||||
-- failure
|
||||
INSERT INTO rls_test_permissive VALUES ('r4','s4',7);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_permissive"
|
||||
ERROR: new row violates row level security policy for "rls_test_permissive"
|
||||
SET ROLE s1;
|
||||
-- With both internal and hook policies, restrictive
|
||||
EXPLAIN (costs off) SELECT * FROM rls_test_restrictive;
|
||||
@ -158,13 +158,13 @@ SELECT * FROM rls_test_restrictive;
|
||||
INSERT INTO rls_test_restrictive VALUES ('r1','s1',8);
|
||||
-- failure
|
||||
INSERT INTO rls_test_restrictive VALUES ('r3','s3',10);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_restrictive"
|
||||
ERROR: new row violates row level security policy for "rls_test_restrictive"
|
||||
-- failure
|
||||
INSERT INTO rls_test_restrictive VALUES ('r1','s1',7);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_restrictive"
|
||||
ERROR: new row violates row level security policy for "rls_test_restrictive"
|
||||
-- failure
|
||||
INSERT INTO rls_test_restrictive VALUES ('r4','s4',7);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_restrictive"
|
||||
ERROR: new row violates row level security policy for "rls_test_restrictive"
|
||||
-- With both internal and hook policies, both permissive
|
||||
-- and restrictive hook policies
|
||||
EXPLAIN (costs off) SELECT * FROM rls_test_both;
|
||||
@ -185,13 +185,13 @@ SELECT * FROM rls_test_both;
|
||||
INSERT INTO rls_test_both VALUES ('r1','s1',8);
|
||||
-- failure
|
||||
INSERT INTO rls_test_both VALUES ('r3','s3',10);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_both"
|
||||
ERROR: new row violates row level security policy for "rls_test_both"
|
||||
-- failure
|
||||
INSERT INTO rls_test_both VALUES ('r1','s1',7);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_both"
|
||||
ERROR: new row violates row level security policy for "rls_test_both"
|
||||
-- failure
|
||||
INSERT INTO rls_test_both VALUES ('r4','s4',7);
|
||||
ERROR: new row violates WITH CHECK OPTION for "rls_test_both"
|
||||
ERROR: new row violates row level security policy for "rls_test_both"
|
||||
RESET ROLE;
|
||||
DROP TABLE rls_test_restrictive;
|
||||
DROP TABLE rls_test_permissive;
|
||||
|
@ -300,6 +300,11 @@ SELECT * FROM document WHERE did = 8; -- and confirm we can't see it
|
||||
-----+-----+--------+---------+--------
|
||||
(0 rows)
|
||||
|
||||
-- RLS policies are checked before constraints
|
||||
INSERT INTO document VALUES (8, 44, 1, 'rls_regress_user2', 'my third manga'); -- Should fail with RLS check violation, not duplicate key violation
|
||||
ERROR: new row violates row level security policy for "document"
|
||||
UPDATE document SET did = 8, dauthor = 'rls_regress_user2' WHERE did = 5; -- Should fail with RLS check violation, not duplicate key violation
|
||||
ERROR: new row violates row level security policy for "document"
|
||||
-- database superuser does bypass RLS policy when enabled
|
||||
RESET SESSION AUTHORIZATION;
|
||||
SET row_security TO ON;
|
||||
@ -1426,9 +1431,9 @@ NOTICE: f_leak => d3d9446802a44259755d38e6d163e820
|
||||
(5 rows)
|
||||
|
||||
INSERT INTO bv1 VALUES (-1, 'xxx'); -- should fail view WCO
|
||||
ERROR: new row violates WITH CHECK OPTION for "b1"
|
||||
ERROR: new row violates row level security policy for "b1"
|
||||
INSERT INTO bv1 VALUES (11, 'xxx'); -- should fail RLS check
|
||||
ERROR: new row violates WITH CHECK OPTION for "b1"
|
||||
ERROR: new row violates row level security policy for "b1"
|
||||
INSERT INTO bv1 VALUES (12, 'xxx'); -- ok
|
||||
EXPLAIN (COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
|
||||
QUERY PLAN
|
||||
@ -1988,7 +1993,7 @@ EXPLAIN (COSTS OFF) WITH cte1 AS (SELECT * FROM t1 WHERE f_leak(b)) SELECT * FRO
|
||||
(6 rows)
|
||||
|
||||
WITH cte1 AS (UPDATE t1 SET a = a + 1 RETURNING *) SELECT * FROM cte1; --fail
|
||||
ERROR: new row violates WITH CHECK OPTION for "t1"
|
||||
ERROR: new row violates row level security policy for "t1"
|
||||
WITH cte1 AS (UPDATE t1 SET a = a RETURNING *) SELECT * FROM cte1; --ok
|
||||
a | b
|
||||
----+----------------------------------
|
||||
@ -2006,7 +2011,7 @@ WITH cte1 AS (UPDATE t1 SET a = a RETURNING *) SELECT * FROM cte1; --ok
|
||||
(11 rows)
|
||||
|
||||
WITH cte1 AS (INSERT INTO t1 VALUES (21, 'Fail') RETURNING *) SELECT * FROM cte1; --fail
|
||||
ERROR: new row violates WITH CHECK OPTION for "t1"
|
||||
ERROR: new row violates row level security policy for "t1"
|
||||
WITH cte1 AS (INSERT INTO t1 VALUES (20, 'Success') RETURNING *) SELECT * FROM cte1; --ok
|
||||
a | b
|
||||
----+---------
|
||||
|
@ -146,6 +146,10 @@ SET SESSION AUTHORIZATION rls_regress_user1;
|
||||
INSERT INTO document VALUES (8, 44, 1, 'rls_regress_user1', 'my third manga'); -- Must fail with unique violation, revealing presence of did we can't see
|
||||
SELECT * FROM document WHERE did = 8; -- and confirm we can't see it
|
||||
|
||||
-- RLS policies are checked before constraints
|
||||
INSERT INTO document VALUES (8, 44, 1, 'rls_regress_user2', 'my third manga'); -- Should fail with RLS check violation, not duplicate key violation
|
||||
UPDATE document SET did = 8, dauthor = 'rls_regress_user2' WHERE did = 5; -- Should fail with RLS check violation, not duplicate key violation
|
||||
|
||||
-- database superuser does bypass RLS policy when enabled
|
||||
RESET SESSION AUTHORIZATION;
|
||||
SET row_security TO ON;
|
||||
|
Reference in New Issue
Block a user