Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Row level security for groups or Making rows accebile to groups

I want the rows in a table accessible to only members of groups. I create users and add them to group by following method,

CREATE USER abc LOGIN PASSWORD 'securedpassword1';
CREATE USER xyz LOGIN PASSWORD 'securedpassword2';

ALTER GROUP permanent ADD USER abc;

Then the policy I write makes it accessible to only current user. But I need whole group to access it.

CREATE TABLE table_Workers
(
    worID INT
    ,worName CHARACTER VARYING
    ,pgUser CHARACTER VARYING
);
INSERT INTO table_Workers VALUES 
(1,'Jason','abc'),(2,'Roy','abc'),(3,'Johny','abc')
,(4,'Jane','xyz'),(5,'Kane','xyz'),(6,'Stuart','xyz');


CREATE POLICY policy_employee_user ON table_Workers FOR ALL
TO PUBLIC USING (pgUser = current_user);

ALTER TABLE table_Workers ENABLE ROW LEVEL SECURITY;

pgUser names the user who can access the row. I wish to replace column pgUser with pgRole, where name of the group is mentioned whose members can access that particular row. Any hint or method is appreciated for making rows accessible to whole group.

like image 666
khaldi Avatar asked Jul 18 '18 11:07

khaldi


2 Answers

This seems to work:

CREATE TABLE workers
(
    worid   int,
    worname text,
    pgrole text[]
);

INSERT INTO workers 
VALUES 
  (1,'Jason','{group1}'),
  (2,'Roy','{group1,group2}'),
  (3,'Johny','{group1}');

CREATE POLICY policy_employee_user ON workers FOR ALL
TO PUBLIC 
   USING ( (select count(*) 
            from unnest(pgrole) r 
            where pg_has_role(current_user, r, 'MEMBER')) > 0 );

ALTER TABLE workers ENABLE ROW LEVEL SECURITY;
like image 182
a_horse_with_no_name Avatar answered Nov 15 '22 09:11

a_horse_with_no_name


db=# create table rls(i int);
CREATE TABLE
Time: 189.439 ms
db=# alter table rls enable row level security ;
ALTER TABLE
Time: 12.725 ms
db=# insert into rls values(1);
INSERT 0 1
Time: 13.241 ms
db=# create user member;
CREATE ROLE
Time: 11.882 ms
db=# create role rls_r;
CREATE ROLE
Time: 9.378 ms
db=# grant rls_r to member ;
GRANT ROLE
Time: 5.704 ms
db=# CREATE POLICY p ON rls FOR ALL TO PUBLIC USING ((select count(*)=1 from pg_auth_members where member = current_user::regrole));
CREATE POLICY
Time: 32.471 ms

now checking:

db=# set role ro ;
SET
Time: 0.350 ms
db=> select * from rls;
 i
---
(0 rows)

Time: 9.801 ms
db=> set role member;
SET
Time: 0.494 ms
db=> select * from rls;
 i
---
 1
(1 row)

Time: 0.694 ms

seems to work...

why such rule?

remember Member of with array in psql when you du role?.. so just:

MacBook-Air:~ vao$ psql db -E
Timing is on.
Pager usage is off.
psql (9.6.1)
Type "help" for help.

db=# \du ro
********* QUERY **********
SELECT r.rolname, r.rolsuper, r.rolinherit,
  r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,
  r.rolconnlimit, r.rolvaliduntil,
  ARRAY(SELECT b.rolname
        FROM pg_catalog.pg_auth_members m
        JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
        WHERE m.member = r.oid) as memberof
, r.rolreplication
, r.rolbypassrls
FROM pg_catalog.pg_roles r
WHERE r.rolname ~ '^(ro)$'
ORDER BY 1;
**************************

            List of roles
 Role name |  Attributes  | Member of
-----------+--------------+-----------
 ro        | Cannot login | {}

and you see the needed query

like image 27
Vao Tsun Avatar answered Nov 15 '22 08:11

Vao Tsun