mirror of
https://git.postgresql.org/git/postgresql.git
synced 2026-02-15 19:06:59 +08:00
ALTER TABLE .. FORCE ROW LEVEL SECURITY
To allow users to force RLS to always be applied, even for table owners, add ALTER TABLE .. FORCE ROW LEVEL SECURITY. row_security=off overrides FORCE ROW LEVEL SECURITY, to ensure pg_dump output is complete (by default). Also add SECURITY_NOFORCE_RLS context to avoid data corruption when ALTER TABLE .. FORCE ROW SECURITY is being used. The SECURITY_NOFORCE_RLS security context is used only during referential integrity checks and is only considered in check_enable_rls() after we have already checked that the current user is the owner of the relation (which should always be the case during referential integrity checks). Back-patch to 9.5 where RLS was added.
This commit is contained in:
@ -1288,6 +1288,141 @@ SET SESSION AUTHORIZATION rls_regress_user0;
|
||||
DROP TABLE r1;
|
||||
DROP TABLE r2;
|
||||
|
||||
--
|
||||
-- FORCE ROW LEVEL SECURITY applies RLS to owners but
|
||||
-- only when row_security = on
|
||||
--
|
||||
SET SESSION AUTHORIZATION rls_regress_user0;
|
||||
SET row_security = on;
|
||||
CREATE TABLE r1 (a int);
|
||||
INSERT INTO r1 VALUES (10), (20);
|
||||
|
||||
CREATE POLICY p1 ON r1 USING (false);
|
||||
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE r1 FORCE ROW LEVEL SECURITY;
|
||||
|
||||
-- No error, but no rows
|
||||
TABLE r1;
|
||||
|
||||
-- RLS error
|
||||
INSERT INTO r1 VALUES (1);
|
||||
|
||||
-- No error (unable to see any rows to update)
|
||||
UPDATE r1 SET a = 1;
|
||||
TABLE r1;
|
||||
|
||||
-- No error (unable to see any rows to delete)
|
||||
DELETE FROM r1;
|
||||
TABLE r1;
|
||||
|
||||
SET row_security = off;
|
||||
-- Shows all rows
|
||||
TABLE r1;
|
||||
|
||||
-- Update all rows
|
||||
UPDATE r1 SET a = 1;
|
||||
TABLE r1;
|
||||
|
||||
-- Delete all rows
|
||||
DELETE FROM r1;
|
||||
TABLE r1;
|
||||
|
||||
DROP TABLE r1;
|
||||
|
||||
--
|
||||
-- FORCE ROW LEVEL SECURITY does not break RI
|
||||
--
|
||||
SET SESSION AUTHORIZATION rls_regress_user0;
|
||||
SET row_security = on;
|
||||
CREATE TABLE r1 (a int PRIMARY KEY);
|
||||
CREATE TABLE r2 (a int REFERENCES r1);
|
||||
INSERT INTO r1 VALUES (10), (20);
|
||||
INSERT INTO r2 VALUES (10), (20);
|
||||
|
||||
-- Create policies on r2 which prevent the
|
||||
-- owner from seeing any rows, but RI should
|
||||
-- still see them.
|
||||
CREATE POLICY p1 ON r2 USING (false);
|
||||
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE r2 FORCE ROW LEVEL SECURITY;
|
||||
|
||||
-- Errors due to rows in r2
|
||||
DELETE FROM r1;
|
||||
|
||||
-- Reset r2 to no-RLS
|
||||
DROP POLICY p1 ON r2;
|
||||
ALTER TABLE r2 NO FORCE ROW LEVEL SECURITY;
|
||||
ALTER TABLE r2 DISABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- clean out r2 for INSERT test below
|
||||
DELETE FROM r2;
|
||||
|
||||
-- Change r1 to not allow rows to be seen
|
||||
CREATE POLICY p1 ON r1 USING (false);
|
||||
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE r1 FORCE ROW LEVEL SECURITY;
|
||||
|
||||
-- No rows seen
|
||||
TABLE r1;
|
||||
|
||||
-- No error, RI still sees that row exists in r1
|
||||
INSERT INTO r2 VALUES (10);
|
||||
|
||||
DROP TABLE r2;
|
||||
DROP TABLE r1;
|
||||
|
||||
-- Ensure cascaded DELETE works
|
||||
CREATE TABLE r1 (a int PRIMARY KEY);
|
||||
CREATE TABLE r2 (a int REFERENCES r1 ON DELETE CASCADE);
|
||||
INSERT INTO r1 VALUES (10), (20);
|
||||
INSERT INTO r2 VALUES (10), (20);
|
||||
|
||||
-- Create policies on r2 which prevent the
|
||||
-- owner from seeing any rows, but RI should
|
||||
-- still see them.
|
||||
CREATE POLICY p1 ON r2 USING (false);
|
||||
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE r2 FORCE ROW LEVEL SECURITY;
|
||||
|
||||
-- Deletes all records from both
|
||||
DELETE FROM r1;
|
||||
|
||||
-- Remove FORCE from r2
|
||||
ALTER TABLE r2 NO FORCE ROW LEVEL SECURITY;
|
||||
|
||||
-- As owner, we now bypass RLS
|
||||
-- verify no rows in r2 now
|
||||
TABLE r2;
|
||||
|
||||
DROP TABLE r2;
|
||||
DROP TABLE r1;
|
||||
|
||||
-- Ensure cascaded UPDATE works
|
||||
CREATE TABLE r1 (a int PRIMARY KEY);
|
||||
CREATE TABLE r2 (a int REFERENCES r1 ON UPDATE CASCADE);
|
||||
INSERT INTO r1 VALUES (10), (20);
|
||||
INSERT INTO r2 VALUES (10), (20);
|
||||
|
||||
-- Create policies on r2 which prevent the
|
||||
-- owner from seeing any rows, but RI should
|
||||
-- still see them.
|
||||
CREATE POLICY p1 ON r2 USING (false);
|
||||
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE r2 FORCE ROW LEVEL SECURITY;
|
||||
|
||||
-- Updates records in both
|
||||
UPDATE r1 SET a = a+5;
|
||||
|
||||
-- Remove FORCE from r2
|
||||
ALTER TABLE r2 NO FORCE ROW LEVEL SECURITY;
|
||||
|
||||
-- As owner, we now bypass RLS
|
||||
-- verify records in r2 updated
|
||||
TABLE r2;
|
||||
|
||||
DROP TABLE r2;
|
||||
DROP TABLE r1;
|
||||
|
||||
--
|
||||
-- Clean up objects
|
||||
--
|
||||
@ -1315,3 +1450,11 @@ CREATE POLICY p1 ON rls_tbl USING (c1 > 5);
|
||||
CREATE POLICY p2 ON rls_tbl FOR SELECT USING (c1 <= 3);
|
||||
CREATE POLICY p3 ON rls_tbl FOR UPDATE USING (c1 <= 3) WITH CHECK (c1 > 5);
|
||||
CREATE POLICY p4 ON rls_tbl FOR DELETE USING (c1 <= 3);
|
||||
|
||||
CREATE TABLE rls_tbl_force (c1 int);
|
||||
ALTER TABLE rls_tbl_force ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE rls_tbl_force FORCE ROW LEVEL SECURITY;
|
||||
CREATE POLICY p1 ON rls_tbl_force USING (c1 = 5) WITH CHECK (c1 < 5);
|
||||
CREATE POLICY p2 ON rls_tbl_force FOR SELECT USING (c1 = 8);
|
||||
CREATE POLICY p3 ON rls_tbl_force FOR UPDATE USING (c1 = 8) WITH CHECK (c1 >= 5);
|
||||
CREATE POLICY p4 ON rls_tbl_force FOR DELETE USING (c1 = 8);
|
||||
|
||||
Reference in New Issue
Block a user