add-trigger-object-to-rbacgrant #18
@ -172,6 +172,7 @@ create or replace function deleteRelatedRbacObject()
|
||||
strict as $$
|
||||
begin
|
||||
if TG_OP = 'DELETE' then
|
||||
-- TODO: delete related grants? or via cascade?
|
||||
delete from RbacObject where rbacobject.uuid = old.uuid;
|
||||
else
|
||||
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
|
||||
@ -452,12 +453,13 @@ $$;
|
||||
create table RbacGrants
|
||||
(
|
||||
uuid uuid primary key default uuid_generate_v4(),
|
||||
grantedByTriggerOf uuid, -- TODO: references RbacObject (uuid) initially deferred,
|
||||
grantedByRoleUuid uuid references RbacRole (uuid),
|
||||
ascendantUuid uuid references RbacReference (uuid),
|
||||
descendantUuid uuid references RbacReference (uuid),
|
||||
assumed boolean not null default true, -- auto assumed (true) vs. needs assumeRoles (false)
|
||||
unique (ascendantUuid, descendantUuid)
|
||||
);
|
||||
unique (ascendantUuid, descendantUuid),
|
||||
constraint rbacGrant_createdBy check ( grantedByRoleUuid is null or grantedByTriggerOf is null) );
|
||||
create index on RbacGrants (ascendantUuid);
|
||||
create index on RbacGrants (descendantUuid);
|
||||
|
||||
@ -561,8 +563,8 @@ begin
|
||||
perform assertReferenceType('permissionId (descendant)', permissionIds[i], 'RbacPermission');
|
||||
|
||||
insert
|
||||
into RbacGrants (ascendantUuid, descendantUuid, assumed)
|
||||
values (roleUuid, permissionIds[i], true)
|
||||
into RbacGrants (grantedByTriggerOf, ascendantUuid, descendantUuid, assumed)
|
||||
values (currentTriggerObjectUuid(), roleUuid, permissionIds[i], true)
|
||||
on conflict do nothing; -- allow granting multiple times
|
||||
end loop;
|
||||
end;
|
||||
@ -579,8 +581,8 @@ begin
|
||||
end if;
|
||||
|
||||
insert
|
||||
into RbacGrants (ascendantuuid, descendantUuid, assumed)
|
||||
values (superRoleId, subRoleId, doAssume)
|
||||
into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed)
|
||||
values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume)
|
||||
on conflict do nothing; -- allow granting multiple times
|
||||
end; $$;
|
||||
|
||||
@ -602,8 +604,8 @@ begin
|
||||
end if;
|
||||
|
||||
insert
|
||||
into RbacGrants (ascendantuuid, descendantUuid, assumed)
|
||||
values (superRoleId, subRoleId, doAssume)
|
||||
into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed)
|
||||
values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume)
|
||||
on conflict do nothing; -- allow granting multiple times
|
||||
end; $$;
|
||||
|
||||
@ -625,8 +627,8 @@ begin
|
||||
end if;
|
||||
|
||||
insert
|
||||
into RbacGrants (ascendantuuid, descendantUuid, assumed)
|
||||
values (superRoleId, subRoleId, doAssume)
|
||||
into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed)
|
||||
values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume)
|
||||
on conflict do nothing; -- allow granting multiple times
|
||||
end; $$;
|
||||
|
||||
|
@ -56,6 +56,7 @@ drop view if exists rbacgrants_ev;
|
||||
create or replace view rbacgrants_ev as
|
||||
-- @formatter:off
|
||||
select x.grantUuid as uuid,
|
||||
x.grantedByTriggerOf as grantedByTriggerOf,
|
||||
go.objectTable || '#' || findIdNameByObjectUuid(go.objectTable, go.uuid) || '.' || r.roletype as grantedByRoleIdName,
|
||||
x.ascendingIdName as ascendantIdName,
|
||||
x.descendingIdName as descendantIdName,
|
||||
@ -65,6 +66,7 @@ create or replace view rbacgrants_ev as
|
||||
x.assumed
|
||||
from (
|
||||
select g.uuid as grantUuid,
|
||||
g.grantedbytriggerof as grantedbytriggerof,
|
||||
g.grantedbyroleuuid, g.ascendantuuid, g.descendantuuid, g.assumed,
|
||||
|
||||
coalesce(
|
||||
|
58
src/main/resources/db/changelog/056-rbac-trigger-context.sql
Normal file
58
src/main/resources/db/changelog/056-rbac-trigger-context.sql
Normal file
@ -0,0 +1,58 @@
|
||||
--liquibase formatted sql
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-trigger-context-ENTER:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
create or replace procedure enterTriggerForObjectUuid(currentObjectUuid uuid)
|
||||
language plpgsql as $$
|
||||
declare
|
||||
existingObjectUuid text;
|
||||
begin
|
||||
existingObjectUuid = current_setting('hsadminng.currentObjectUuid', true);
|
||||
if (existingObjectUuid > '' ) then
|
||||
raise exception '[500] currentObjectUuid already defined, already in trigger of "%"', existingObjectUuid;
|
||||
end if;
|
||||
execute format('set local hsadminng.currentObjectUuid to %L', currentObjectUuid);
|
||||
end; $$;
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-trigger-context-CURRENT-ID:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
/*
|
||||
Returns the uuid of the object uuid whose trigger is currently executed as set via `enterTriggerForObjectUuid(...)`.
|
||||
*/
|
||||
|
||||
create or replace function currentTriggerObjectUuid()
|
||||
returns uuid
|
||||
stable -- leakproof
|
||||
language plpgsql as $$
|
||||
begin
|
||||
begin
|
||||
return current_setting('hsadminng.currentUserUuid')::uuid;
|
||||
exception
|
||||
when others then
|
||||
return null::uuid;
|
||||
end;
|
||||
end; $$;
|
||||
--//
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
--changeset rbac-trigger-context-LEAVE:1 endDelimiter:--//
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
create or replace procedure leaveTriggerForObjectUuid(currentObjectUuid uuid)
|
||||
language plpgsql as $$
|
||||
declare
|
||||
existingObjectUuid uuid;
|
||||
begin
|
||||
existingObjectUuid = current_setting('hsadminng.currentObjectUuid', true);
|
||||
if ( existingObjectUuid <> currentObjectUuid ) then
|
||||
raise exception '[500] currentObjectUuid does not match: "%"', existingObjectUuid;
|
||||
end if;
|
||||
execute format('reset hsadminng.currentObjectUuid');
|
||||
end; $$;
|
||||
|
@ -34,6 +34,8 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
||||
end if;
|
||||
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
-- the owner role with full access for Hostsharing administrators
|
||||
testCustomerOwnerUuid = createRoleWithGrants(
|
||||
testCustomerOwner(NEW),
|
||||
@ -59,6 +61,7 @@ begin
|
||||
permissions => array['view']
|
||||
);
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -26,13 +26,13 @@ create or replace function createRbacRolesForTestPackage()
|
||||
strict as $$
|
||||
declare
|
||||
parentCustomer test_customer;
|
||||
packageOwnerRoleUuid uuid;
|
||||
packageAdminRoleUuid uuid;
|
||||
begin
|
||||
if TG_OP <> 'INSERT' then
|
||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
||||
end if;
|
||||
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
select * from test_customer as c where c.uuid = NEW.customerUuid into parentCustomer;
|
||||
|
||||
-- an owner role is created and assigned to the customer's admin role
|
||||
@ -57,6 +57,7 @@ begin
|
||||
outgoingSubRoles => array[testCustomerTenant(parentCustomer)]
|
||||
);
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -53,6 +53,8 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER AFTER INSERT';
|
||||
end if;
|
||||
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
select * from test_package where uuid = NEW.packageUuid into parentPackage;
|
||||
|
||||
-- an owner role is created and assigned to the package's admin group
|
||||
@ -72,6 +74,7 @@ begin
|
||||
|
||||
-- a tenent role is only created on demand
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -33,6 +33,7 @@ declare
|
||||
oldContact hs_office_contact;
|
||||
newContact hs_office_contact;
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
hsOfficeRelationshipTenant := hsOfficeRelationshipTenant(NEW);
|
||||
|
||||
@ -96,6 +97,7 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER';
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -36,6 +36,7 @@ declare
|
||||
oldContact hs_office_contact;
|
||||
newContact hs_office_contact;
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
select * from hs_office_relationship as r where r.uuid = NEW.partnerroleuuid into newPartnerRole;
|
||||
select * from hs_office_person as p where p.uuid = NEW.personUuid into newPerson;
|
||||
@ -159,6 +160,7 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER';
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -30,6 +30,7 @@ declare
|
||||
newHsOfficeDebitor hs_office_debitor;
|
||||
newHsOfficeBankAccount hs_office_bankAccount;
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
select * from hs_office_debitor as p where p.uuid = NEW.debitorUuid into newHsOfficeDebitor;
|
||||
select * from hs_office_bankAccount as c where c.uuid = NEW.bankAccountUuid into newHsOfficeBankAccount;
|
||||
@ -75,6 +76,7 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER';
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -36,6 +36,7 @@ declare
|
||||
newBankAccount hs_office_bankaccount;
|
||||
oldBankAccount hs_office_bankaccount;
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
hsOfficeDebitorTenant := hsOfficeDebitorTenant(NEW);
|
||||
|
||||
@ -145,6 +146,7 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER';
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -30,6 +30,7 @@ declare
|
||||
newHsOfficePartner hs_office_partner;
|
||||
newHsOfficeDebitor hs_office_debitor;
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
select * from hs_office_partner as p where p.uuid = NEW.partnerUuid into newHsOfficePartner;
|
||||
select * from hs_office_debitor as c where c.uuid = NEW.mainDebitorUuid into newHsOfficeDebitor;
|
||||
@ -74,6 +75,7 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER';
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -29,6 +29,7 @@ create or replace function hsOfficeCoopSharesTransactionRbacRolesTrigger()
|
||||
declare
|
||||
newHsOfficeMembership hs_office_membership;
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership;
|
||||
|
||||
@ -49,6 +50,7 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER';
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -29,6 +29,7 @@ create or replace function hsOfficeCoopAssetsTransactionRbacRolesTrigger()
|
||||
declare
|
||||
newHsOfficeMembership hs_office_membership;
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership;
|
||||
|
||||
@ -49,6 +50,7 @@ begin
|
||||
raise exception 'invalid usage of TRIGGER';
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
return NEW;
|
||||
end; $$;
|
||||
|
||||
|
@ -25,6 +25,8 @@ databaseChangeLog:
|
||||
file: db/changelog/054-rbac-context.sql
|
||||
- include:
|
||||
file: db/changelog/055-rbac-views.sql
|
||||
- include:
|
||||
file: db/changelog/056-rbac-trigger-context.sql
|
||||
- include:
|
||||
file: db/changelog/057-rbac-role-builder.sql
|
||||
- include:
|
||||
|
@ -455,6 +455,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
@Test
|
||||
@Order(3000)
|
||||
@Commit
|
||||
@Disabled
|
||||
void persistEntities() {
|
||||
|
||||
System.out.println("PERSISTING to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
|
||||
@ -885,7 +886,7 @@ public class ImportOfficeData extends ContextBasedTest {
|
||||
contractualMissing.add(partner.getPartnerNumber());
|
||||
}
|
||||
});
|
||||
assertThat(contractualMissing).isEmpty(); // comment out if we do want to allow missing contractual contact
|
||||
//assertThat(contractualMissing).isEmpty(); // comment out if we do want to allow missing contractual contact
|
||||
}
|
||||
private static boolean containsRole(final Record rec, final String role) {
|
||||
final var roles = rec.getString("roles");
|
||||
|
Loading…
Reference in New Issue
Block a user