changeset 4740:2440d2f86f4e

Authorize sections based on country of creator Disregarding the area of resposibility will allow to create sections outside of the country of the user in order to allow data analysis and aggregation based on sections spanning over multiple countries.
author Tom Gottfried <tom@intevation.de>
date Fri, 18 Oct 2019 12:04:04 +0200
parents 257dd6039a28
children 5164b4450c42
files schema/auth.sql schema/auth_tests.sql schema/gemma.sql schema/manage_users.sql schema/manage_users_tests.sql schema/updates/1308/01.add_section_country.sql schema/version.sql
diffstat 7 files changed, 76 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/schema/auth.sql	Fri Oct 18 12:01:21 2019 +0200
+++ b/schema/auth.sql	Fri Oct 18 12:04:04 2019 +0200
@@ -149,9 +149,10 @@
     FOR ALL TO waterway_admin
     USING (users.utm_covers(area));
 
-CREATE POLICY responsibility_area ON waterway.sections
+CREATE POLICY same_country ON waterway.sections
     FOR ALL TO waterway_admin
-    USING (users.utm_covers(area));
+    USING (country = (
+        SELECT country FROM users.list_users WHERE username = current_user));
 
 CREATE POLICY sys_admin ON users.stretches
     FOR ALL TO sys_admin
--- a/schema/auth_tests.sql	Fri Oct 18 12:01:21 2019 +0200
+++ b/schema/auth_tests.sql	Fri Oct 18 12:04:04 2019 +0200
@@ -15,17 +15,6 @@
 -- pgTAP test script for privileges and RLS policies
 --
 
--- Helper function:
-CREATE OR REPLACE FUNCTION users.current_user_country()
-    RETURNS internal.user_profiles.country%TYPE
-    AS $$
-        SELECT country FROM users.list_users
-            WHERE username = current_user
-    $$
-    LANGUAGE SQL
-    STABLE PARALLEL SAFE;
-
-
 CREATE FUNCTION test_privs() RETURNS SETOF TEXT AS
 $$
 DECLARE the_schema CONSTANT varchar = 'waterway';
@@ -75,7 +64,7 @@
     'User should see templates associated to his country');
 
 SELECT ok(
-    users.current_user_country() = ALL(
+    users.user_country() = ALL(
         SELECT country FROM users.templates),
     'User should only see templates associated to his country');
 
--- a/schema/gemma.sql	Fri Oct 18 12:01:21 2019 +0200
+++ b/schema/gemma.sql	Fri Oct 18 12:04:04 2019 +0200
@@ -440,9 +440,43 @@
     )
     CREATE TRIGGER templates_date_info BEFORE UPDATE ON templates
         FOR EACH ROW EXECUTE PROCEDURE update_date_info()
+
+    CREATE VIEW users.list_users WITH (security_barrier) AS
+        SELECT
+            r.rolname,
+            p.username,
+            CAST('' AS varchar) AS pw,
+            p.country,
+            p.map_extent,
+            p.email_address
+        FROM internal.user_profiles p
+            JOIN pg_roles u ON p.username = u.rolname
+            JOIN pg_auth_members a ON u.oid = a.member
+            JOIN pg_roles r ON a.roleid = r.oid
+        WHERE p.username = current_user
+            OR pg_has_role('waterway_admin', 'MEMBER')
+                AND p.country = (
+                    SELECT country FROM internal.user_profiles
+                        WHERE username = current_user)
+            OR pg_has_role('sys_admin', 'MEMBER')
 ;
 
 
+--
+-- Functions to be used in DEFAULT expresions
+--
+
+-- Return current_user's country code
+CREATE FUNCTION users.user_country(user_name name DEFAULT current_user)
+    RETURNS internal.user_profiles.country%TYPE
+    AS $$
+        SELECT country FROM users.list_users
+            WHERE username = user_name
+    $$
+    LANGUAGE SQL
+    STABLE PARALLEL SAFE;
+
+
 -- Namespace for waterway data that can change in a running system
 CREATE SCHEMA waterway
 
@@ -589,6 +623,8 @@
             CHECK(ST_IsValid(CAST(area AS geometry))),
         objnam varchar NOT NULL,
         nobjnam varchar,
+        country char(2) NOT NULL REFERENCES countries
+            DEFAULT users.user_country(),
         date_info timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
         source_organization varchar NOT NULL,
         staging_done boolean NOT NULL DEFAULT false,
--- a/schema/manage_users.sql	Fri Oct 18 12:01:21 2019 +0200
+++ b/schema/manage_users.sql	Fri Oct 18 12:04:04 2019 +0200
@@ -38,26 +38,6 @@
     LANGUAGE plpgsql;
 
 
-CREATE OR REPLACE VIEW users.list_users WITH (security_barrier) AS
-    SELECT
-            r.rolname,
-            p.username,
-            CAST('' AS varchar) AS pw,
-            p.country,
-            p.map_extent,
-            p.email_address
-        FROM internal.user_profiles p
-            JOIN pg_roles u ON p.username = u.rolname
-            JOIN pg_auth_members a ON u.oid = a.member
-            JOIN pg_roles r ON a.roleid = r.oid
-        WHERE p.username = current_user
-            OR pg_has_role('waterway_admin', 'MEMBER')
-                AND p.country = (
-                    SELECT country FROM internal.user_profiles
-                        WHERE username = current_user)
-            OR pg_has_role('sys_admin', 'MEMBER');
-
-
 CREATE OR REPLACE FUNCTION users.current_user_area_utm()
     RETURNS geometry
     AS $$
--- a/schema/manage_users_tests.sql	Fri Oct 18 12:01:21 2019 +0200
+++ b/schema/manage_users_tests.sql	Fri Oct 18 12:04:04 2019 +0200
@@ -28,7 +28,7 @@
     SELECT best_utm(ST_Collect(area::geometry))
         FROM users.stretches st
             JOIN users.stretch_countries stc ON stc.stretch_id = st.id
-        WHERE country = users.current_user_country()
+        WHERE country = users.user_country()
     $$,
     'Geometry has SRID corresponding to best_utm()');
 
@@ -169,7 +169,7 @@
     UPDATE users.list_users
         SET (pw, map_extent, email_address)
             = ('user_at2!', 'BOX(0 0,1 1)', 'user_at_test')
-        WHERE country = users.current_user_country()
+        WHERE country = users.user_country()
             AND username <> current_user
         RETURNING *
     $$,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/schema/updates/1308/01.add_section_country.sql	Fri Oct 18 12:04:04 2019 +0200
@@ -0,0 +1,33 @@
+CREATE FUNCTION users.user_country(user_name name DEFAULT current_user)
+    RETURNS internal.user_profiles.country%TYPE
+    AS $$
+        SELECT country FROM users.list_users
+            WHERE username = user_name
+    $$
+    LANGUAGE SQL
+    STABLE PARALLEL SAFE;
+
+ALTER TABLE waterway.sections ADD country char(2) REFERENCES countries
+    DEFAULT users.user_country();
+
+-- Try to find out the country of existing sections:
+UPDATE waterway.sections s SET country = (
+    SELECT COALESCE(
+        users.user_country((
+            SELECT i.username
+                FROM import.imports i
+                    JOIN import.import_logs ON i.id = import_id
+                WHERE i.kind = 'sec'
+                    AND (state = 'accepted' AND s.staging_done
+                        OR state = 'pending' AND NOT s.staging_done)
+                    AND msg = 'Storing section ''' || s.name || ''''
+                ORDER BY i.enqueued DESC FETCH FIRST ROW ONLY)),
+        '--'));
+
+ALTER TABLE waterway.sections ALTER country SET NOT NULL;
+
+DROP POLICY responsibility_area ON waterway.sections;
+CREATE POLICY same_country ON waterway.sections
+    FOR ALL TO waterway_admin
+    USING (country = (
+        SELECT country FROM users.list_users WHERE username = current_user));
--- a/schema/version.sql	Fri Oct 18 12:01:21 2019 +0200
+++ b/schema/version.sql	Fri Oct 18 12:04:04 2019 +0200
@@ -1,1 +1,1 @@
-INSERT INTO gemma_schema_version(version) VALUES (1307);
+INSERT INTO gemma_schema_version(version) VALUES (1308);