formatted SQL code
This commit is contained in:
parent
fb8862c37e
commit
4c403b0436
@ -1,22 +1,21 @@
|
||||
|
||||
|
||||
|
||||
CREATE TABLE Hostsharing
|
||||
create table Hostsharing
|
||||
(
|
||||
uuid uuid PRIMARY KEY REFERENCES RbacObject(uuid)
|
||||
uuid uuid primary key references RbacObject (uuid)
|
||||
);
|
||||
CREATE UNIQUE INDEX Hostsharing_Singleton ON Hostsharing ((0));
|
||||
create unique index Hostsharing_Singleton on Hostsharing ((0));
|
||||
|
||||
|
||||
INSERT INTO RbacObject (objecttable) VALUES ('hostsharing');
|
||||
INSERT INTO Hostsharing (uuid) VALUES ((SELECT uuid FROM RbacObject WHERE objectTable='hostsharing'));
|
||||
insert
|
||||
into RbacObject (objecttable) values ('hostsharing');
|
||||
insert
|
||||
into Hostsharing (uuid) values ((select uuid from RbacObject where objectTable = 'hostsharing'));
|
||||
|
||||
CREATE OR REPLACE FUNCTION hostsharingAdmin()
|
||||
RETURNS RbacRoleDescriptor
|
||||
RETURNS NULL ON NULL INPUT
|
||||
STABLE LEAKPROOF
|
||||
LANGUAGE sql AS $$
|
||||
SELECT 'global', (SELECT uuid FROM RbacObject WHERE objectTable='hostsharing'), 'admin'::RbacRoleType;
|
||||
create or replace function hostsharingAdmin()
|
||||
returns RbacRoleDescriptor
|
||||
returns null on null input
|
||||
stable leakproof
|
||||
language sql as $$
|
||||
select 'global', (select uuid from RbacObject where objectTable = 'hostsharing'), 'admin'::RbacRoleType;
|
||||
$$;
|
||||
|
||||
-- create administrators role with two assigned users
|
||||
@ -32,7 +31,7 @@ do language plpgsql $$
|
||||
$$;
|
||||
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
SET LOCAL hsadminng.currentUser = 'mike@hostsharing.net';
|
||||
select * from RbacUser where uuid=currentUserId();
|
||||
END TRANSACTION;
|
||||
begin transaction;
|
||||
set local hsadminng.currentUser = 'mike@hostsharing.net';
|
||||
select * from RbacUser where uuid = currentUserId();
|
||||
end transaction;
|
||||
|
@ -15,11 +15,11 @@ create or replace function intToVarChar(i integer, len integer)
|
||||
declare
|
||||
partial varchar;
|
||||
begin
|
||||
select chr(ascii('a') + i%26) into partial;
|
||||
select chr(ascii('a') + i % 26) into partial;
|
||||
if len > 1 then
|
||||
return intToVarChar(i/26, len-1) || partial;
|
||||
return intToVarChar(i / 26, len - 1) || partial;
|
||||
else
|
||||
return partial;
|
||||
end if;
|
||||
END; $$;
|
||||
end; $$;
|
||||
--//
|
||||
|
@ -12,9 +12,9 @@
|
||||
create or replace function randomInRange(min integer, max integer)
|
||||
returns integer
|
||||
returns null on null input
|
||||
language 'plpgsql' AS $$
|
||||
language 'plpgsql' as $$
|
||||
begin
|
||||
return floor(random() * (max-min + 1) + min);
|
||||
return floor(random() * (max - min + 1) + min);
|
||||
end; $$;
|
||||
--//
|
||||
|
||||
|
@ -5,5 +5,5 @@
|
||||
/*
|
||||
Makes improved uuid generation available.
|
||||
*/
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
create extension if not exists "uuid-ossp";
|
||||
--//
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,17 +9,18 @@
|
||||
|
||||
*/
|
||||
|
||||
CREATE TYPE RbacPermissions AS
|
||||
create type RbacPermissions as
|
||||
(
|
||||
permissionUuids uuid[]
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION grantingPermissions(forObjectUuid uuid, permitOps RbacOp[])
|
||||
RETURNS RbacPermissions
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
BEGIN
|
||||
RETURN ROW(createPermissions(forObjectUuid, permitOps))::RbacPermissions;
|
||||
END; $$;
|
||||
create or replace function grantingPermissions(forObjectUuid uuid, permitOps RbacOp[])
|
||||
returns RbacPermissions
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return row (createPermissions(forObjectUuid, permitOps))::RbacPermissions;
|
||||
end; $$;
|
||||
|
||||
--//
|
||||
|
||||
@ -28,45 +29,50 @@ END; $$;
|
||||
/*
|
||||
|
||||
*/
|
||||
CREATE TYPE RbacSuperRoles AS
|
||||
create type RbacSuperRoles as
|
||||
(
|
||||
roleUuids uuid[]
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION beneathRoles(roleDescriptors RbacRoleDescriptor[])
|
||||
RETURNS RbacSuperRoles
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
DECLARE
|
||||
create or replace function beneathRoles(roleDescriptors RbacRoleDescriptor[])
|
||||
returns RbacSuperRoles
|
||||
language plpgsql
|
||||
strict as $$
|
||||
declare
|
||||
superRoleDescriptor RbacRoleDescriptor;
|
||||
superRoleUuids uuid[] := ARRAY[]::uuid[];
|
||||
BEGIN
|
||||
FOREACH superRoleDescriptor IN ARRAY roleDescriptors LOOP
|
||||
superRoleUuids := superRoleUuids || getRoleId(superRoleDescriptor, 'fail');
|
||||
END LOOP;
|
||||
superRoleUuids uuid[] := array []::uuid[];
|
||||
begin
|
||||
foreach superRoleDescriptor in array roleDescriptors
|
||||
loop
|
||||
superRoleUuids := superRoleUuids || getRoleId(superRoleDescriptor, 'fail');
|
||||
end loop;
|
||||
|
||||
RETURN ROW(superRoleUuids)::RbacSuperRoles;
|
||||
END; $$;
|
||||
return row (superRoleUuids)::RbacSuperRoles;
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION beneathRole(roleDescriptor RbacRoleDescriptor)
|
||||
RETURNS RbacSuperRoles
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
BEGIN
|
||||
RETURN beneathRoles(ARRAY[roleDescriptor]);
|
||||
END; $$;
|
||||
create or replace function beneathRole(roleDescriptor RbacRoleDescriptor)
|
||||
returns RbacSuperRoles
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return beneathRoles(array [roleDescriptor]);
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION beneathRole(roleUuid uuid)
|
||||
RETURNS RbacSuperRoles
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
BEGIN
|
||||
RETURN ROW(ARRAY[roleUuid]::uuid[])::RbacSuperRoles;
|
||||
END; $$;
|
||||
create or replace function beneathRole(roleUuid uuid)
|
||||
returns RbacSuperRoles
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return row (array [roleUuid]::uuid[])::RbacSuperRoles;
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION asTopLevelRole()
|
||||
RETURNS RbacSuperRoles
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
BEGIN
|
||||
RETURN ROW(ARRAY[]::uuid[])::RbacSuperRoles;
|
||||
END; $$;
|
||||
create or replace function asTopLevelRole()
|
||||
returns RbacSuperRoles
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return row (array []::uuid[])::RbacSuperRoles;
|
||||
end; $$;
|
||||
|
||||
--//
|
||||
|
||||
@ -78,26 +84,28 @@ END; $$;
|
||||
/*
|
||||
|
||||
*/
|
||||
CREATE TYPE RbacSubRoles AS
|
||||
create type RbacSubRoles as
|
||||
(
|
||||
roleUuids uuid[]
|
||||
);
|
||||
|
||||
-- drop FUNCTION beingItselfA(roleUuid uuid)
|
||||
CREATE OR REPLACE FUNCTION beingItselfA(roleUuid uuid)
|
||||
RETURNS RbacSubRoles
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
BEGIN
|
||||
RETURN ROW(ARRAY[roleUuid]::uuid[])::RbacSubRoles;
|
||||
END; $$;
|
||||
create or replace function beingItselfA(roleUuid uuid)
|
||||
returns RbacSubRoles
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return row (array [roleUuid]::uuid[])::RbacSubRoles;
|
||||
end; $$;
|
||||
|
||||
-- drop FUNCTION beingItselfA(roleDescriptor RbacRoleDescriptor)
|
||||
CREATE OR REPLACE FUNCTION beingItselfA(roleDescriptor RbacRoleDescriptor)
|
||||
RETURNS RbacSubRoles
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
BEGIN
|
||||
RETURN beingItselfA(getRoleId(roleDescriptor, 'fail'));
|
||||
END; $$;
|
||||
create or replace function beingItselfA(roleDescriptor RbacRoleDescriptor)
|
||||
returns RbacSubRoles
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return beingItselfA(getRoleId(roleDescriptor, 'fail'));
|
||||
end; $$;
|
||||
|
||||
--//
|
||||
|
||||
@ -108,33 +116,35 @@ END; $$;
|
||||
|
||||
/*
|
||||
*/
|
||||
CREATE TYPE RbacUsers AS
|
||||
create type RbacUsers as
|
||||
(
|
||||
userUuids uuid[]
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION withUsers(userNames varchar[])
|
||||
RETURNS RbacUsers
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
DECLARE
|
||||
userName varchar;
|
||||
userUuids uuid[] := ARRAY[]::uuid[];
|
||||
BEGIN
|
||||
FOREACH userName IN ARRAY userNames LOOP
|
||||
userUuids := userUuids || getRbacUserId(userName, 'fail');
|
||||
END LOOP;
|
||||
create or replace function withUsers(userNames varchar[])
|
||||
returns RbacUsers
|
||||
language plpgsql
|
||||
strict as $$
|
||||
declare
|
||||
userName varchar;
|
||||
userUuids uuid[] := array []::uuid[];
|
||||
begin
|
||||
foreach userName in array userNames
|
||||
loop
|
||||
userUuids := userUuids || getRbacUserId(userName, 'fail');
|
||||
end loop;
|
||||
|
||||
RETURN ROW(userUuids)::RbacUsers;
|
||||
END; $$;
|
||||
return row (userUuids)::RbacUsers;
|
||||
end; $$;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION withUser(userName varchar, whenNotExists RbacWhenNotExists = 'fail')
|
||||
RETURNS RbacUsers
|
||||
RETURNS NULL ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
RETURN ROW(ARRAY[getRbacUserId(userName, whenNotExists )]);
|
||||
END; $$;
|
||||
create or replace function withUser(userName varchar, whenNotExists RbacWhenNotExists = 'fail')
|
||||
returns RbacUsers
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return row (array [getRbacUserId(userName, whenNotExists)]);
|
||||
end; $$;
|
||||
|
||||
--//
|
||||
|
||||
@ -145,72 +155,75 @@ END; $$;
|
||||
|
||||
/*
|
||||
*/
|
||||
CREATE OR REPLACE FUNCTION createRole(
|
||||
create or replace function createRole(
|
||||
roleDescriptor RbacRoleDescriptor,
|
||||
permissions RbacPermissions,
|
||||
superRoles RbacSuperRoles,
|
||||
subRoles RbacSubRoles = null,
|
||||
users RbacUsers = null
|
||||
)
|
||||
RETURNS uuid
|
||||
CALLED ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
DECLARE
|
||||
roleUuid uuid;
|
||||
returns uuid
|
||||
called on null input
|
||||
language plpgsql as $$
|
||||
declare
|
||||
roleUuid uuid;
|
||||
superRoleUuid uuid;
|
||||
subRoleUuid uuid;
|
||||
userUuid uuid;
|
||||
BEGIN
|
||||
RAISE NOTICE 'will createRole for %', roleDescriptor;
|
||||
RAISE NOTICE 'will createRole for % % %', roleDescriptor.objecttable, roleDescriptor.objectuuid, roleDescriptor.roletype;
|
||||
subRoleUuid uuid;
|
||||
userUuid uuid;
|
||||
begin
|
||||
raise notice 'will createRole for %', roleDescriptor;
|
||||
raise notice 'will createRole for % % %', roleDescriptor.objecttable, roleDescriptor.objectuuid, roleDescriptor.roletype;
|
||||
roleUuid = createRole(roleDescriptor);
|
||||
|
||||
call grantPermissionsToRole(roleUuid, permissions.permissionUuids);
|
||||
|
||||
IF superRoles IS NOT NULL THEN
|
||||
FOREACH superRoleUuid IN ARRAY superRoles.roleuUids LOOP
|
||||
call grantRoleToRole(roleUuid, superRoleUuid);
|
||||
END LOOP;
|
||||
END IF;
|
||||
if superRoles is not null then
|
||||
foreach superRoleUuid in array superRoles.roleuUids
|
||||
loop
|
||||
call grantRoleToRole(roleUuid, superRoleUuid);
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
IF subRoles IS NOT NULL THEN
|
||||
FOREACH subRoleUuid IN ARRAY subRoles.roleuUids LOOP
|
||||
call grantRoleToRole(subRoleUuid, roleUuid);
|
||||
END LOOP;
|
||||
END IF;
|
||||
if subRoles is not null then
|
||||
foreach subRoleUuid in array subRoles.roleuUids
|
||||
loop
|
||||
call grantRoleToRole(subRoleUuid, roleUuid);
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
IF users IS NOT NULL THEN
|
||||
FOREACH userUuid IN ARRAY users.useruUids LOOP
|
||||
call grantRoleToUser(roleUuid, userUuid);
|
||||
END LOOP;
|
||||
END IF;
|
||||
if users is not null then
|
||||
foreach userUuid in array users.useruUids
|
||||
loop
|
||||
call grantRoleToUser(roleUuid, userUuid);
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
RETURN roleUuid;
|
||||
END; $$;
|
||||
return roleUuid;
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION createRole(
|
||||
create or replace function createRole(
|
||||
roleDescriptor RbacRoleDescriptor,
|
||||
permissions RbacPermissions,
|
||||
users RbacUsers = null
|
||||
)
|
||||
RETURNS uuid
|
||||
CALLED ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
RETURN createRole(roleDescriptor, permissions, null, null, users);
|
||||
END; $$;
|
||||
returns uuid
|
||||
called on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return createRole(roleDescriptor, permissions, null, null, users);
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION createRole(
|
||||
create or replace function createRole(
|
||||
roleDescriptor RbacRoleDescriptor,
|
||||
permissions RbacPermissions,
|
||||
subRoles RbacSubRoles,
|
||||
users RbacUsers = null
|
||||
)
|
||||
RETURNS uuid
|
||||
CALLED ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
BEGIN
|
||||
RETURN createRole(roleDescriptor, permissions, null, subRoles, users);
|
||||
END; $$;
|
||||
returns uuid
|
||||
called on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return createRole(roleDescriptor, permissions, null, subRoles, users);
|
||||
end; $$;
|
||||
|
||||
--//
|
||||
|
@ -5,20 +5,24 @@
|
||||
/*
|
||||
Creates a view which presents some statistics about the RBAC tables.
|
||||
*/
|
||||
create view RbacStatisticsView AS
|
||||
select no, to_char("count", '9 999 999 999') as "count", "table"
|
||||
from (
|
||||
select 1 as no, count(*) as "count", 'login users' as "table" from RbacUser
|
||||
union
|
||||
select 2 as no, count(*) as "count", 'roles' as "table" from RbacRole
|
||||
union
|
||||
select 3 as no, count(*) as "count", 'permissions' as "table" from RbacPermission
|
||||
union
|
||||
select 4 as no, count(*) as "count", 'references' as "table" from RbacReference
|
||||
union
|
||||
select 5 as no, count(*) as "count", 'grants' as "table" from RbacGrants
|
||||
union
|
||||
select 6 as no, count(*) as "count", 'objects' as "table" from RbacObject
|
||||
) as totals
|
||||
create view RbacStatisticsView as
|
||||
select no, to_char("count", '9 999 999 999') as "count", "table"
|
||||
from (select 1 as no, count(*) as "count", 'login users' as "table"
|
||||
from RbacUser
|
||||
union
|
||||
select 2 as no, count(*) as "count", 'roles' as "table"
|
||||
from RbacRole
|
||||
union
|
||||
select 3 as no, count(*) as "count", 'permissions' as "table"
|
||||
from RbacPermission
|
||||
union
|
||||
select 4 as no, count(*) as "count", 'references' as "table"
|
||||
from RbacReference
|
||||
union
|
||||
select 5 as no, count(*) as "count", 'grants' as "table"
|
||||
from RbacGrants
|
||||
union
|
||||
select 6 as no, count(*) as "count", 'objects' as "table"
|
||||
from RbacObject) as totals
|
||||
order by totals.no;
|
||||
--//
|
||||
|
183
src/main/resources/db/changelog/2022-07-28-051-hs-customer.sql
Normal file
183
src/main/resources/db/changelog/2022-07-28-051-hs-customer.sql
Normal file
@ -0,0 +1,183 @@
|
||||
-- ========================================================
|
||||
-- Customer example with RBAC
|
||||
-- --------------------------------------------------------
|
||||
|
||||
set session session authorization default;
|
||||
|
||||
create table if not exists customer
|
||||
(
|
||||
uuid uuid unique references RbacObject (uuid),
|
||||
reference int not null unique check (reference between 10000 and 99999),
|
||||
prefix character(3) unique,
|
||||
adminUserName varchar(63)
|
||||
);
|
||||
|
||||
drop trigger if exists createRbacObjectForCustomer_Trigger on customer;
|
||||
create trigger createRbacObjectForCustomer_Trigger
|
||||
before insert
|
||||
on customer
|
||||
for each row
|
||||
execute procedure createRbacObject();
|
||||
|
||||
create or replace function customerOwner(customer customer)
|
||||
returns RbacRoleDescriptor
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return roleDescriptor('customer', customer.uuid, 'owner');
|
||||
end; $$;
|
||||
|
||||
create or replace function customerAdmin(customer customer)
|
||||
returns RbacRoleDescriptor
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return roleDescriptor('customer', customer.uuid, 'admin');
|
||||
end; $$;
|
||||
|
||||
create or replace function customerTenant(customer customer)
|
||||
returns RbacRoleDescriptor
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
return roleDescriptor('customer', customer.uuid, 'tenant');
|
||||
end; $$;
|
||||
|
||||
|
||||
create or replace function createRbacRulesForCustomer()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
strict as $$
|
||||
declare
|
||||
customerOwnerUuid uuid;
|
||||
customerAdminUuid uuid;
|
||||
begin
|
||||
if TG_OP <> 'INSERT' then
|
||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
||||
end if;
|
||||
|
||||
-- the owner role with full access for Hostsharing administrators
|
||||
customerOwnerUuid = createRole(
|
||||
customerOwner(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']),
|
||||
beneathRole(hostsharingAdmin())
|
||||
);
|
||||
|
||||
-- the admin role for the customer's admins, who can view and add products
|
||||
customerAdminUuid = createRole(
|
||||
customerAdmin(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view', 'add-package']),
|
||||
-- NO auto follow for customer owner to avoid exploding permissions for administrators
|
||||
withUser(NEW.adminUserName, 'create') -- implicitly ignored if null
|
||||
);
|
||||
|
||||
-- allow the customer owner role (thus administrators) to assume the customer admin role
|
||||
call grantRoleToRole(customerAdminUuid, customerOwnerUuid, false);
|
||||
|
||||
-- the tenant role which later can be used by owners+admins of sub-objects
|
||||
perform createRole(
|
||||
customerTenant(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view'])
|
||||
);
|
||||
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
drop trigger if exists createRbacRulesForCustomer_Trigger on customer;
|
||||
create trigger createRbacRulesForCustomer_Trigger
|
||||
after insert
|
||||
on customer
|
||||
for each row
|
||||
execute procedure createRbacRulesForCustomer();
|
||||
|
||||
create or replace function deleteRbacRulesForCustomer()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
strict as $$
|
||||
declare
|
||||
objectTable varchar = 'customer';
|
||||
begin
|
||||
if TG_OP = 'DELETE' then
|
||||
|
||||
-- delete the owner role (for admininstrators)
|
||||
call deleteRole(findRoleId(objectTable || '#' || NEW.prefix || '.owner'));
|
||||
|
||||
-- delete the customer admin role
|
||||
call deleteRole(findRoleId(objectTable || '#' || NEW.prefix || '.admin'));
|
||||
else
|
||||
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
|
||||
end if;
|
||||
end; $$;
|
||||
|
||||
drop trigger if exists deleteRbacRulesForCustomer_Trigger on customer;
|
||||
create trigger deleteRbacRulesForCustomer_Trigger
|
||||
before delete
|
||||
on customer
|
||||
for each row
|
||||
execute procedure deleteRbacRulesForCustomer();
|
||||
|
||||
-- create a restricted view to access the textual customer ids a idName
|
||||
set session session authorization default;
|
||||
-- ALTER TABLE customer ENABLE ROW LEVEL SECURITY;
|
||||
drop view if exists customer_iv;
|
||||
create or replace view customer_iv as
|
||||
select distinct target.uuid, target.prefix as idName
|
||||
from customer as target;
|
||||
-- TODO: Is it ok that everybody has access to this information?
|
||||
grant all privileges on customer_iv to restricted;
|
||||
|
||||
create or replace function customerUuidByIdName(idName varchar)
|
||||
returns uuid
|
||||
language sql
|
||||
strict as $$
|
||||
select uuid from customer_iv iv where iv.idName = customerUuidByIdName.idName;
|
||||
$$;
|
||||
|
||||
-- create RBAC restricted view
|
||||
set session session authorization default;
|
||||
-- ALTER TABLE customer ENABLE ROW LEVEL SECURITY;
|
||||
drop view if exists customer_rv;
|
||||
create or replace view customer_rv as
|
||||
select distinct target.*
|
||||
from customer as target
|
||||
where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'customer', currentSubjectIds()));
|
||||
grant all privileges on customer_rv to restricted;
|
||||
|
||||
|
||||
-- generate Customer test data
|
||||
|
||||
set session session authorization default;
|
||||
do language plpgsql $$
|
||||
declare
|
||||
currentTask varchar;
|
||||
custReference integer;
|
||||
custRowId uuid;
|
||||
custPrefix varchar;
|
||||
custAdminName varchar;
|
||||
begin
|
||||
set hsadminng.currentUser to '';
|
||||
|
||||
for t in 0..9
|
||||
loop
|
||||
currentTask = 'creating RBAC test customer #' || t;
|
||||
set local hsadminng.currentUser to 'mike@hostsharing.net';
|
||||
set local hsadminng.assumedRoles = '';
|
||||
set local hsadminng.currentTask to currentTask;
|
||||
|
||||
-- When a new customer is created,
|
||||
custReference = 10000 + t;
|
||||
custRowId = uuid_generate_v4();
|
||||
custPrefix = intToVarChar(t, 3);
|
||||
custAdminName = 'admin@' || custPrefix || '.example.com';
|
||||
|
||||
raise notice 'creating customer %:%', custReference, custPrefix;
|
||||
insert
|
||||
into customer (reference, prefix, adminUserName)
|
||||
values (custReference, custPrefix, custAdminName);
|
||||
|
||||
commit;
|
||||
|
||||
end loop;
|
||||
|
||||
end;
|
||||
$$;
|
@ -1,169 +0,0 @@
|
||||
|
||||
-- ========================================================
|
||||
-- Customer example with RBAC
|
||||
-- --------------------------------------------------------
|
||||
|
||||
SET SESSION SESSION AUTHORIZATION DEFAULT ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS customer (
|
||||
uuid uuid UNIQUE REFERENCES RbacObject(uuid),
|
||||
reference int not null unique CHECK (reference BETWEEN 10000 AND 99999),
|
||||
prefix character(3) unique,
|
||||
adminUserName varchar(63)
|
||||
);
|
||||
|
||||
DROP TRIGGER IF EXISTS createRbacObjectForCustomer_Trigger ON customer;
|
||||
CREATE TRIGGER createRbacObjectForCustomer_Trigger
|
||||
BEFORE INSERT ON customer
|
||||
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
||||
|
||||
CREATE OR REPLACE FUNCTION customerOwner(customer customer)
|
||||
RETURNS RbacRoleDescriptor
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
begin
|
||||
return roleDescriptor('customer', customer.uuid, 'owner');
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION customerAdmin(customer customer)
|
||||
RETURNS RbacRoleDescriptor
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
begin
|
||||
return roleDescriptor('customer', customer.uuid, 'admin');
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION customerTenant(customer customer)
|
||||
RETURNS RbacRoleDescriptor
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
begin
|
||||
return roleDescriptor('customer', customer.uuid, 'tenant');
|
||||
end; $$;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION createRbacRulesForCustomer()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
DECLARE
|
||||
customerOwnerUuid uuid;
|
||||
customerAdminUuid uuid;
|
||||
BEGIN
|
||||
IF TG_OP <> 'INSERT' THEN
|
||||
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
||||
END IF;
|
||||
|
||||
-- the owner role with full access for Hostsharing administrators
|
||||
customerOwnerUuid = createRole(
|
||||
customerOwner(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||
beneathRole(hostsharingAdmin())
|
||||
);
|
||||
|
||||
-- the admin role for the customer's admins, who can view and add products
|
||||
customerAdminUuid = createRole(
|
||||
customerAdmin(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['view', 'add-package']),
|
||||
-- NO auto follow for customer owner to avoid exploding permissions for administrators
|
||||
withUser(NEW.adminUserName, 'create') -- implicitly ignored if null
|
||||
);
|
||||
|
||||
-- allow the customer owner role (thus administrators) to assume the customer admin role
|
||||
call grantRoleToRole(customerAdminUuid, customerOwnerUuid, FALSE);
|
||||
|
||||
-- the tenant role which later can be used by owners+admins of sub-objects
|
||||
perform createRole(
|
||||
customerTenant(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['view'])
|
||||
);
|
||||
|
||||
RETURN NEW;
|
||||
END; $$;
|
||||
|
||||
DROP TRIGGER IF EXISTS createRbacRulesForCustomer_Trigger ON customer;
|
||||
CREATE TRIGGER createRbacRulesForCustomer_Trigger
|
||||
AFTER INSERT ON customer
|
||||
FOR EACH ROW EXECUTE PROCEDURE createRbacRulesForCustomer();
|
||||
|
||||
CREATE OR REPLACE FUNCTION deleteRbacRulesForCustomer()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
DECLARE
|
||||
objectTable varchar = 'customer';
|
||||
BEGIN
|
||||
IF TG_OP = 'DELETE' THEN
|
||||
|
||||
-- delete the owner role (for admininstrators)
|
||||
call deleteRole(findRoleId(objectTable||'#'||NEW.prefix||'.owner'));
|
||||
|
||||
-- delete the customer admin role
|
||||
call deleteRole(findRoleId(objectTable||'#'||NEW.prefix||'.admin'));
|
||||
ELSE
|
||||
RAISE EXCEPTION 'invalid usage of TRIGGER BEFORE DELETE';
|
||||
END IF;
|
||||
END; $$;
|
||||
|
||||
DROP TRIGGER IF EXISTS deleteRbacRulesForCustomer_Trigger ON customer;
|
||||
CREATE TRIGGER deleteRbacRulesForCustomer_Trigger
|
||||
BEFORE DELETE ON customer
|
||||
FOR EACH ROW EXECUTE PROCEDURE deleteRbacRulesForCustomer();
|
||||
|
||||
-- create a restricted view to access the textual customer ids a idName
|
||||
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||
-- ALTER TABLE customer ENABLE ROW LEVEL SECURITY;
|
||||
DROP VIEW IF EXISTS customer_iv;
|
||||
CREATE OR REPLACE VIEW customer_iv AS
|
||||
SELECT DISTINCT target.uuid, target.prefix as idName
|
||||
FROM customer AS target;
|
||||
-- TODO: Is it ok that everybody has access to this information?
|
||||
GRANT ALL PRIVILEGES ON customer_iv TO restricted;
|
||||
|
||||
CREATE OR REPLACE FUNCTION customerUuidByIdName(idName varchar)
|
||||
RETURNS uuid
|
||||
LANGUAGE sql STRICT AS $$
|
||||
SELECT uuid FROM customer_iv iv WHERE iv.idName=customerUuidByIdName.idName;
|
||||
$$;
|
||||
|
||||
-- create RBAC restricted view
|
||||
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||
-- ALTER TABLE customer ENABLE ROW LEVEL SECURITY;
|
||||
DROP VIEW IF EXISTS customer_rv;
|
||||
CREATE OR REPLACE VIEW customer_rv AS
|
||||
SELECT DISTINCT target.*
|
||||
FROM customer AS target
|
||||
WHERE target.uuid IN (SELECT queryAccessibleObjectUuidsOfSubjectIds( 'view', 'customer', currentSubjectIds()));
|
||||
GRANT ALL PRIVILEGES ON customer_rv TO restricted;
|
||||
|
||||
|
||||
-- generate Customer test data
|
||||
|
||||
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||
DO LANGUAGE plpgsql $$
|
||||
DECLARE
|
||||
currentTask varchar;
|
||||
custReference integer;
|
||||
custRowId uuid;
|
||||
custPrefix varchar;
|
||||
custAdminName varchar;
|
||||
BEGIN
|
||||
SET hsadminng.currentUser TO '';
|
||||
|
||||
FOR t IN 0..9 LOOP
|
||||
currentTask = 'creating RBAC test customer #' || t;
|
||||
SET LOCAL hsadminng.currentUser TO 'mike@hostsharing.net';
|
||||
SET LOCAL hsadminng.assumedRoles = '';
|
||||
SET LOCAL hsadminng.currentTask TO currentTask;
|
||||
|
||||
-- When a new customer is created,
|
||||
custReference = 10000 + t;
|
||||
custRowId = uuid_generate_v4();
|
||||
custPrefix = intToVarChar(t, 3 );
|
||||
custAdminName = 'admin@' || custPrefix || '.example.com';
|
||||
|
||||
raise notice 'creating customer %:%', custReference, custPrefix;
|
||||
insert into customer (reference, prefix, adminUserName)
|
||||
VALUES (custReference, custPrefix, custAdminName);
|
||||
|
||||
COMMIT;
|
||||
|
||||
END LOOP;
|
||||
|
||||
END;
|
||||
$$;
|
@ -1,149 +1,161 @@
|
||||
|
||||
-- ========================================================
|
||||
-- Package example with RBAC
|
||||
-- --------------------------------------------------------
|
||||
|
||||
SET SESSION SESSION AUTHORIZATION DEFAULT ;
|
||||
set session session authorization default;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS package (
|
||||
uuid uuid UNIQUE REFERENCES RbacObject(uuid),
|
||||
name character varying(5),
|
||||
customerUuid uuid REFERENCES customer(uuid)
|
||||
create table if not exists package
|
||||
(
|
||||
uuid uuid unique references RbacObject (uuid),
|
||||
name character varying(5),
|
||||
customerUuid uuid references customer (uuid)
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION packageOwner(pac package)
|
||||
RETURNS RbacRoleDescriptor
|
||||
RETURNS NULL ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
create or replace function packageOwner(pac package)
|
||||
returns RbacRoleDescriptor
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
declare
|
||||
roleDesc RbacRoleDescriptor;
|
||||
begin
|
||||
return roleDescriptor('package', pac.uuid, 'admin');
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION packageAdmin(pac package)
|
||||
RETURNS RbacRoleDescriptor
|
||||
RETURNS NULL ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
create or replace function packageAdmin(pac package)
|
||||
returns RbacRoleDescriptor
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return roleDescriptor('package', pac.uuid, 'admin');
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION packageTenant(pac package)
|
||||
RETURNS RbacRoleDescriptor
|
||||
RETURNS NULL ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
create or replace function packageTenant(pac package)
|
||||
returns RbacRoleDescriptor
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return roleDescriptor('package', pac.uuid, 'tenant');
|
||||
end; $$;
|
||||
|
||||
|
||||
DROP TRIGGER IF EXISTS createRbacObjectForPackage_Trigger ON package;
|
||||
CREATE TRIGGER createRbacObjectForPackage_Trigger
|
||||
BEFORE INSERT ON package
|
||||
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
||||
drop trigger if exists createRbacObjectForPackage_Trigger on package;
|
||||
create trigger createRbacObjectForPackage_Trigger
|
||||
before insert
|
||||
on package
|
||||
for each row
|
||||
execute procedure createRbacObject();
|
||||
|
||||
CREATE OR REPLACE FUNCTION createRbacRulesForPackage()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
DECLARE
|
||||
parentCustomer customer;
|
||||
create or replace function createRbacRulesForPackage()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
strict as $$
|
||||
declare
|
||||
parentCustomer customer;
|
||||
packageOwnerRoleUuid uuid;
|
||||
packageAdminRoleUuid uuid;
|
||||
BEGIN
|
||||
IF TG_OP <> 'INSERT' THEN
|
||||
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
||||
END IF;
|
||||
begin
|
||||
if TG_OP <> 'INSERT' then
|
||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
||||
end if;
|
||||
|
||||
SELECT * FROM customer AS c WHERE c.uuid=NEW.customerUuid INTO parentCustomer;
|
||||
select * from customer as c where c.uuid = NEW.customerUuid into parentCustomer;
|
||||
|
||||
-- an owner role is created and assigned to the customer's admin role
|
||||
packageOwnerRoleUuid = createRole(
|
||||
packageOwner(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']),
|
||||
beneathRole(customerAdmin(parentCustomer))
|
||||
);
|
||||
|
||||
-- an owner role is created and assigned to the package owner role
|
||||
packageAdminRoleUuid = createRole(
|
||||
packageAdmin(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['edit', 'add-unixuser', 'add-domain']),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit', 'add-unixuser', 'add-domain']),
|
||||
beneathRole(packageOwnerRoleUuid)
|
||||
);
|
||||
|
||||
-- and a package tenant role is created and assigned to the package admin as well
|
||||
perform createRole(
|
||||
packageTenant(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY ['view']),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']),
|
||||
beneathRole(packageAdminRoleUuid),
|
||||
beingItselfA(customerTenant(parentCustomer))
|
||||
);
|
||||
|
||||
RETURN NEW;
|
||||
END; $$;
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
DROP TRIGGER IF EXISTS createRbacRulesForPackage_Trigger ON package;
|
||||
CREATE TRIGGER createRbacRulesForPackage_Trigger
|
||||
AFTER INSERT ON package
|
||||
FOR EACH ROW EXECUTE PROCEDURE createRbacRulesForPackage();
|
||||
drop trigger if exists createRbacRulesForPackage_Trigger on package;
|
||||
create trigger createRbacRulesForPackage_Trigger
|
||||
after insert
|
||||
on package
|
||||
for each row
|
||||
execute procedure createRbacRulesForPackage();
|
||||
|
||||
CREATE OR REPLACE FUNCTION deleteRbacRulesForPackage()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
BEGIN
|
||||
IF TG_OP = 'DELETE' THEN
|
||||
create or replace function deleteRbacRulesForPackage()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
strict as $$
|
||||
begin
|
||||
if TG_OP = 'DELETE' then
|
||||
-- TODO
|
||||
ELSE
|
||||
RAISE EXCEPTION 'invalid usage of TRIGGER BEFORE DELETE';
|
||||
END IF;
|
||||
END; $$;
|
||||
else
|
||||
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
|
||||
end if;
|
||||
end; $$;
|
||||
|
||||
DROP TRIGGER IF EXISTS deleteRbacRulesForPackage_Trigger ON customer;
|
||||
CREATE TRIGGER deleteRbacRulesForPackage_Trigger
|
||||
BEFORE DELETE ON customer
|
||||
FOR EACH ROW EXECUTE PROCEDURE deleteRbacRulesForPackage();
|
||||
drop trigger if exists deleteRbacRulesForPackage_Trigger on customer;
|
||||
create trigger deleteRbacRulesForPackage_Trigger
|
||||
before delete
|
||||
on customer
|
||||
for each row
|
||||
execute procedure deleteRbacRulesForPackage();
|
||||
|
||||
-- create RBAC-restricted view
|
||||
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||
set session session authorization default;
|
||||
-- ALTER TABLE package ENABLE ROW LEVEL SECURITY;
|
||||
DROP VIEW IF EXISTS package_rv;
|
||||
CREATE OR REPLACE VIEW package_rv AS
|
||||
SELECT DISTINCT target.*
|
||||
FROM package AS target
|
||||
WHERE target.uuid IN (SELECT queryAccessibleObjectUuidsOfSubjectIds( 'view', 'package', currentSubjectIds()));
|
||||
GRANT ALL PRIVILEGES ON package_rv TO restricted;
|
||||
drop view if exists package_rv;
|
||||
create or replace view package_rv as
|
||||
select distinct target.*
|
||||
from package as target
|
||||
where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'package', currentSubjectIds()));
|
||||
grant all privileges on package_rv to restricted;
|
||||
|
||||
|
||||
-- generate Package test data
|
||||
|
||||
DO LANGUAGE plpgsql $$
|
||||
DECLARE
|
||||
cust customer;
|
||||
pacName varchar;
|
||||
do language plpgsql $$
|
||||
declare
|
||||
cust customer;
|
||||
pacName varchar;
|
||||
currentTask varchar;
|
||||
custAdmin varchar;
|
||||
BEGIN
|
||||
SET hsadminng.currentUser TO '';
|
||||
custAdmin varchar;
|
||||
begin
|
||||
set hsadminng.currentUser to '';
|
||||
|
||||
FOR cust IN (SELECT * FROM customer) LOOP
|
||||
-- CONTINUE WHEN cust.reference < 18000;
|
||||
for cust in (select * from customer)
|
||||
loop
|
||||
-- CONTINUE WHEN cust.reference < 18000;
|
||||
|
||||
FOR t IN 0..randominrange(1, 2) LOOP
|
||||
pacName = cust.prefix || TO_CHAR(t, 'fm00');
|
||||
currentTask = 'creating RBAC test package #'|| pacName || ' for customer ' || cust.prefix || ' #' || cust.uuid;
|
||||
RAISE NOTICE 'task: %', currentTask;
|
||||
for t in 0..randominrange(1, 2)
|
||||
loop
|
||||
pacName = cust.prefix || to_char(t, 'fm00');
|
||||
currentTask = 'creating RBAC test package #' || pacName || ' for customer ' || cust.prefix || ' #' ||
|
||||
cust.uuid;
|
||||
raise notice 'task: %', currentTask;
|
||||
|
||||
custAdmin = 'admin@' || cust.prefix || '.example.com';
|
||||
SET LOCAL hsadminng.currentUser TO custAdmin;
|
||||
SET LOCAL hsadminng.assumedRoles = '';
|
||||
SET LOCAL hsadminng.currentTask TO currentTask;
|
||||
custAdmin = 'admin@' || cust.prefix || '.example.com';
|
||||
set local hsadminng.currentUser to custAdmin;
|
||||
set local hsadminng.assumedRoles = '';
|
||||
set local hsadminng.currentTask to currentTask;
|
||||
|
||||
insert into package (name, customerUuid)
|
||||
VALUES (pacName, cust.uuid);
|
||||
insert
|
||||
into package (name, customerUuid)
|
||||
values (pacName, cust.uuid);
|
||||
|
||||
COMMIT;
|
||||
END LOOP;
|
||||
END LOOP;
|
||||
END;
|
||||
commit;
|
||||
end loop;
|
||||
end loop;
|
||||
end;
|
||||
$$;
|
||||
|
||||
|
@ -1,152 +1,159 @@
|
||||
|
||||
-- ========================================================
|
||||
-- UnixUser example with RBAC
|
||||
-- --------------------------------------------------------
|
||||
|
||||
SET SESSION SESSION AUTHORIZATION DEFAULT ;
|
||||
set session session authorization default;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS UnixUser (
|
||||
uuid uuid UNIQUE REFERENCES RbacObject(uuid),
|
||||
name character varying(32),
|
||||
comment character varying(96),
|
||||
packageUuid uuid REFERENCES package(uuid)
|
||||
create table if not exists UnixUser
|
||||
(
|
||||
uuid uuid unique references RbacObject (uuid),
|
||||
name character varying(32),
|
||||
comment character varying(96),
|
||||
packageUuid uuid references package (uuid)
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION unixUserOwner(uu UnixUser)
|
||||
RETURNS RbacRoleDescriptor
|
||||
RETURNS NULL ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
create or replace function unixUserOwner(uu UnixUser)
|
||||
returns RbacRoleDescriptor
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return roleDescriptor('unixuser', uu.uuid, 'owner');
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION unixUserAdmin(uu UnixUser)
|
||||
RETURNS RbacRoleDescriptor
|
||||
RETURNS NULL ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
create or replace function unixUserAdmin(uu UnixUser)
|
||||
returns RbacRoleDescriptor
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return roleDescriptor('unixuser', uu.uuid, 'admin');
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION unixUserTenant(uu UnixUser)
|
||||
RETURNS RbacRoleDescriptor
|
||||
RETURNS NULL ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
create or replace function unixUserTenant(uu UnixUser)
|
||||
returns RbacRoleDescriptor
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
begin
|
||||
return roleDescriptor('unixuser', uu.uuid, 'tenant');
|
||||
end; $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION createUnixUserTenantRoleIfNotExists(unixUser UnixUser)
|
||||
RETURNS uuid
|
||||
RETURNS NULL ON NULL INPUT
|
||||
LANGUAGE plpgsql AS $$
|
||||
DECLARE
|
||||
create or replace function createUnixUserTenantRoleIfNotExists(unixUser UnixUser)
|
||||
returns uuid
|
||||
returns null on null input
|
||||
language plpgsql as $$
|
||||
declare
|
||||
unixUserTenantRoleDesc RbacRoleDescriptor;
|
||||
unixUserTenantRoleUuid uuid;
|
||||
BEGIN
|
||||
begin
|
||||
unixUserTenantRoleDesc = unixUserTenant(unixUser);
|
||||
unixUserTenantRoleUuid = findRoleId(unixUserTenantRoleDesc);
|
||||
IF unixUserTenantRoleUuid IS NOT NULL THEN
|
||||
RETURN unixUserTenantRoleUuid;
|
||||
END IF;
|
||||
if unixUserTenantRoleUuid is not null then
|
||||
return unixUserTenantRoleUuid;
|
||||
end if;
|
||||
|
||||
RETURN createRole(
|
||||
return createRole(
|
||||
unixUserTenantRoleDesc,
|
||||
grantingPermissions(forObjectUuid => unixUser.uuid, permitOps => ARRAY['view']),
|
||||
grantingPermissions(forObjectUuid => unixUser.uuid, permitOps => array ['view']),
|
||||
beneathRole(unixUserAdmin(unixUser))
|
||||
);
|
||||
END; $$;
|
||||
end; $$;
|
||||
|
||||
|
||||
DROP TRIGGER IF EXISTS createRbacObjectForUnixUser_Trigger ON UnixUser;
|
||||
CREATE TRIGGER createRbacObjectForUnixUser_Trigger
|
||||
BEFORE INSERT ON UnixUser
|
||||
FOR EACH ROW EXECUTE PROCEDURE createRbacObject();
|
||||
drop trigger if exists createRbacObjectForUnixUser_Trigger on UnixUser;
|
||||
create trigger createRbacObjectForUnixUser_Trigger
|
||||
before insert
|
||||
on UnixUser
|
||||
for each row
|
||||
execute procedure createRbacObject();
|
||||
|
||||
CREATE OR REPLACE FUNCTION createRbacRulesForUnixUser()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql STRICT AS $$
|
||||
DECLARE
|
||||
parentPackage package;
|
||||
create or replace function createRbacRulesForUnixUser()
|
||||
returns trigger
|
||||
language plpgsql
|
||||
strict as $$
|
||||
declare
|
||||
parentPackage package;
|
||||
unixuserOwnerRoleId uuid;
|
||||
unixuserAdminRoleId uuid;
|
||||
BEGIN
|
||||
IF TG_OP <> 'INSERT' THEN
|
||||
RAISE EXCEPTION 'invalid usage of TRIGGER AFTER INSERT';
|
||||
END IF;
|
||||
begin
|
||||
if TG_OP <> 'INSERT' then
|
||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
||||
end if;
|
||||
|
||||
SELECT * FROM package WHERE uuid=NEW.packageUuid into parentPackage;
|
||||
select * from package where uuid = NEW.packageUuid into parentPackage;
|
||||
|
||||
-- an owner role is created and assigned to the package's admin group
|
||||
unixuserOwnerRoleId = createRole(
|
||||
unixUserOwner(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['*']),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']),
|
||||
beneathRole(packageAdmin(parentPackage))
|
||||
);
|
||||
|
||||
-- and a unixuser admin role is created and assigned to the unixuser owner as well
|
||||
unixuserAdminRoleId = createRole(
|
||||
unixUserAdmin(NEW),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => ARRAY['edit']),
|
||||
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']),
|
||||
beneathRole(unixuserOwnerRoleId),
|
||||
beingItselfA(packageTenant(parentPackage))
|
||||
);
|
||||
|
||||
-- a tenent role is only created on demand
|
||||
|
||||
RETURN NEW;
|
||||
END; $$;
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
DROP TRIGGER IF EXISTS createRbacRulesForUnixUser_Trigger ON UnixUser;
|
||||
CREATE TRIGGER createRbacRulesForUnixUser_Trigger
|
||||
AFTER INSERT ON UnixUser
|
||||
FOR EACH ROW EXECUTE PROCEDURE createRbacRulesForUnixUser();
|
||||
drop trigger if exists createRbacRulesForUnixUser_Trigger on UnixUser;
|
||||
create trigger createRbacRulesForUnixUser_Trigger
|
||||
after insert
|
||||
on UnixUser
|
||||
for each row
|
||||
execute procedure createRbacRulesForUnixUser();
|
||||
|
||||
-- TODO: CREATE OR REPLACE FUNCTION deleteRbacRulesForUnixUser()
|
||||
|
||||
|
||||
-- create RBAC-restricted view
|
||||
SET SESSION SESSION AUTHORIZATION DEFAULT;
|
||||
set session session authorization default;
|
||||
-- ALTER TABLE unixuser ENABLE ROW LEVEL SECURITY;
|
||||
DROP VIEW IF EXISTS unixuser_rv;
|
||||
CREATE OR REPLACE VIEW unixuser_rv AS
|
||||
SELECT DISTINCT target.*
|
||||
FROM unixuser AS target
|
||||
WHERE target.uuid IN (SELECT queryAccessibleObjectUuidsOfSubjectIds( 'view', 'unixuser', currentSubjectIds()));
|
||||
GRANT ALL PRIVILEGES ON unixuser_rv TO restricted;
|
||||
drop view if exists unixuser_rv;
|
||||
create or replace view unixuser_rv as
|
||||
select distinct target.*
|
||||
from unixuser as target
|
||||
where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('view', 'unixuser', currentSubjectIds()));
|
||||
grant all privileges on unixuser_rv to restricted;
|
||||
|
||||
|
||||
-- generate UnixUser test data
|
||||
|
||||
DO LANGUAGE plpgsql $$
|
||||
DECLARE
|
||||
pac record;
|
||||
pacAdmin varchar;
|
||||
do language plpgsql $$
|
||||
declare
|
||||
pac record;
|
||||
pacAdmin varchar;
|
||||
currentTask varchar;
|
||||
BEGIN
|
||||
SET hsadminng.currentUser TO '';
|
||||
begin
|
||||
set hsadminng.currentUser to '';
|
||||
|
||||
FOR pac IN (
|
||||
SELECT p.uuid, p.name
|
||||
FROM package p
|
||||
JOIN customer c ON p.customeruuid = c.uuid
|
||||
-- WHERE c.reference >= 18000
|
||||
) LOOP
|
||||
for pac in (select p.uuid, p.name
|
||||
from package p
|
||||
join customer c on p.customeruuid = c.uuid
|
||||
-- WHERE c.reference >= 18000
|
||||
)
|
||||
loop
|
||||
|
||||
FOR t IN 0..9 LOOP
|
||||
currentTask = 'creating RBAC test unixuser #' || t || ' for package ' || pac.name|| ' #' || pac.uuid;
|
||||
RAISE NOTICE 'task: %', currentTask;
|
||||
pacAdmin = 'admin@' || pac.name || '.example.com';
|
||||
SET LOCAL hsadminng.currentUser TO 'mike@hostsharing.net'; -- TODO: use a package-admin
|
||||
SET LOCAL hsadminng.assumedRoles = '';
|
||||
SET LOCAL hsadminng.currentTask TO currentTask;
|
||||
for t in 0..9
|
||||
loop
|
||||
currentTask = 'creating RBAC test unixuser #' || t || ' for package ' || pac.name || ' #' || pac.uuid;
|
||||
raise notice 'task: %', currentTask;
|
||||
pacAdmin = 'admin@' || pac.name || '.example.com';
|
||||
set local hsadminng.currentUser to 'mike@hostsharing.net'; -- TODO: use a package-admin
|
||||
set local hsadminng.assumedRoles = '';
|
||||
set local hsadminng.currentTask to currentTask;
|
||||
|
||||
INSERT INTO unixuser (name, packageUuid)
|
||||
VALUES (pac.name||'-'|| intToVarChar(t, 4), pac.uuid);
|
||||
insert
|
||||
into unixuser (name, packageUuid)
|
||||
values (pac.name || '-' || intToVarChar(t, 4), pac.uuid);
|
||||
|
||||
COMMIT;
|
||||
END LOOP;
|
||||
END LOOP;
|
||||
commit;
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
END;
|
||||
end;
|
||||
$$;
|
||||
|