summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorStephen Frost2015-10-05 01:05:08 +0000
committerStephen Frost2015-10-05 01:05:08 +0000
commit088c83363a11200f2225f279d4a5c6cc6f9db3d2 (patch)
treef5568ba1294ab5695d5f67b9f79f96130e60c44a /src/test
parent16a70e3059885739f59ccdaa20f2e4a3b2a0a700 (diff)
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.
Diffstat (limited to 'src/test')
-rw-r--r--src/test/modules/test_ddl_deparse/test_ddl_deparse.c6
-rw-r--r--src/test/regress/expected/rowsecurity.out156
-rw-r--r--src/test/regress/output/misc.source3
-rw-r--r--src/test/regress/sql/rowsecurity.sql143
4 files changed, 307 insertions, 1 deletions
diff --git a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
index e2dc4b5c768..4fca7373b0a 100644
--- a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
+++ b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
@@ -275,6 +275,12 @@ get_altertable_subcmdtypes(PG_FUNCTION_ARGS)
case AT_DisableRowSecurity:
strtype = "DISABLE ROW SECURITY";
break;
+ case AT_ForceRowSecurity:
+ strtype = "FORCE ROW SECURITY";
+ break;
+ case AT_NoForceRowSecurity:
+ strtype = "NO FORCE ROW SECURITY";
+ break;
case AT_GenericOptions:
strtype = "SET OPTIONS";
break;
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 0363dfd07ff..a050444cd0c 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -3009,6 +3009,155 @@ 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;
+ a
+---
+(0 rows)
+
+-- RLS error
+INSERT INTO r1 VALUES (1);
+ERROR: new row violates row level security policy for "r1"
+-- No error (unable to see any rows to update)
+UPDATE r1 SET a = 1;
+TABLE r1;
+ a
+---
+(0 rows)
+
+-- No error (unable to see any rows to delete)
+DELETE FROM r1;
+TABLE r1;
+ a
+---
+(0 rows)
+
+SET row_security = off;
+-- Shows all rows
+TABLE r1;
+ a
+----
+ 10
+ 20
+(2 rows)
+
+-- Update all rows
+UPDATE r1 SET a = 1;
+TABLE r1;
+ a
+---
+ 1
+ 1
+(2 rows)
+
+-- Delete all rows
+DELETE FROM r1;
+TABLE r1;
+ a
+---
+(0 rows)
+
+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;
+ERROR: update or delete on table "r1" violates foreign key constraint "r2_a_fkey" on table "r2"
+DETAIL: Key (a)=(10) is still referenced from table "r2".
+-- 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;
+ a
+---
+(0 rows)
+
+-- 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;
+ a
+---
+(0 rows)
+
+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;
+ a
+----
+ 15
+ 25
+(2 rows)
+
+DROP TABLE r2;
+DROP TABLE r1;
+--
-- Clean up objects
--
RESET SESSION AUTHORIZATION;
@@ -3031,3 +3180,10 @@ 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);
diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source
index 44147638188..5f263f9a3a1 100644
--- a/src/test/regress/output/misc.source
+++ b/src/test/regress/output/misc.source
@@ -672,6 +672,7 @@ SELECT user_relns() AS user_relns
real_city
reltime_tbl
rls_tbl
+ rls_tbl_force
road
shighway
slow_emp4000
@@ -709,7 +710,7 @@ SELECT user_relns() AS user_relns
tvvmv
varchar_tbl
xacttest
-(131 rows)
+(132 rows)
SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
name
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index 7f8772fa26c..070c452a77c 100644
--- a/src/test/regress/sql/rowsecurity.sql
+++ b/src/test/regress/sql/rowsecurity.sql
@@ -1289,6 +1289,141 @@ 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
--
RESET SESSION AUTHORIZATION;
@@ -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);