introduce referrer role and support explict columns for restricted view

This commit is contained in:
Michael Hoennig 2024-03-24 11:01:45 +01:00
parent fbe2204d72
commit c9f7d8ec2d
13 changed files with 202 additions and 178 deletions

View File

@ -94,4 +94,17 @@ public class RbacGrantController implements RbacGrantsApi {
return ResponseEntity.noContent().build(); return ResponseEntity.noContent().build();
} }
// TODO: implement an endpoint to create a Mermaid flowchart with all grants of a given user
// @GetMapping(
// path = "/api/rbac/users/{userUuid}/grants",
// produces = {"text/vnd.mermaid"})
// @Transactional(readOnly = true)
// public ResponseEntity<String> allGrantsOfUserAsMermaid(
// @RequestHeader(name = "current-user") String currentUser,
// @RequestHeader(name = "assumed-roles", required = false) String assumedRoles) {
// final var graph = RbacGrantsDiagramService.allGrantsToUser(currentUser);
// return ResponseEntity.ok(graph);
// }
} }

View File

@ -1,5 +1,5 @@
package net.hostsharing.hsadminng.rbac.rbacrole; package net.hostsharing.hsadminng.rbac.rbacrole;
public enum RbacRoleType { public enum RbacRoleType {
owner, admin, agent, tenant, guest owner, admin, agent, tenant, guest, referrer
} }

View File

@ -0,0 +1,20 @@
--liquibase formatted sql
-- ============================================================================
-- TABLE-COLUMNS-FUNCTION
--changeset table-columns-function:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
create or replace function columnsNames( tableName text )
returns text
stable
language 'plpgsql' as $$
declare columns text[];
begin
columns := (select array(select column_name::text
from information_schema.columns
where table_name = tableName));
return array_to_string(columns, ', ');
end; $$
--//

View File

@ -164,7 +164,7 @@ end; $$;
*/ */
create type RbacRoleType as enum ('owner', 'admin', 'agent', 'tenant', 'guest'); create type RbacRoleType as enum ('owner', 'admin', 'agent', 'tenant', 'guest', 'referrer');
create table RbacRole create table RbacRole
( (
@ -373,10 +373,12 @@ create table RbacPermission
uuid uuid primary key references RbacReference (uuid) on delete cascade, uuid uuid primary key references RbacReference (uuid) on delete cascade,
objectUuid uuid not null references RbacObject, objectUuid uuid not null references RbacObject,
op RbacOp not null, op RbacOp not null,
opTableName varchar(60), opTableName varchar(60)
unique (objectUuid, op)
); );
ALTER TABLE RbacPermission
ADD CONSTRAINT RbacPermission_uc UNIQUE NULLS NOT DISTINCT (objectUuid, op, opTableName);
call create_journal('RbacPermission'); call create_journal('RbacPermission');
create or replace function createPermission(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null) create or replace function createPermission(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null)
@ -395,7 +397,10 @@ begin
raise exception 'forOpTableName must only be specified for ops: [INSERT]'; -- currently no other raise exception 'forOpTableName must only be specified for ops: [INSERT]'; -- currently no other
end if; end if;
permissionUuid = (select uuid from RbacPermission where objectUuid = forObjectUuid and op = forOp and opTableName = forOpTableName); permissionUuid := (
select uuid from RbacPermission
where objectUuid = forObjectUuid
and op = forOp and opTableName is not distinct from forOpTableName);
if (permissionUuid is null) then if (permissionUuid is null) then
insert into RbacReference ("type") insert into RbacReference ("type")
values ('RbacPermission') values ('RbacPermission')
@ -466,8 +471,44 @@ select uuid
and p.op = forOp and p.op = forOp
and p.opTableName = forOpTableName and p.opTableName = forOpTableName
$$; $$;
create or replace function getPermissionId(forObjectUuid uuid, forOp RbacOp, forOpTableName text = null)
returns uuid
stable -- leakproof
language plpgsql as $$
declare
permissionUuid uuid;
begin
select uuid into permissionUuid
from RbacPermission p
where p.objectUuid = forObjectUuid
and p.op = forOp
and forOpTableName is null or p.opTableName = forOpTableName;
assert permissionUuid is not null,
format('permission %s %s for object UUID %s cannot be found', forOp, forOpTableName, forObjectUuid);
return permissionUuid;
end; $$;
--// --//
-- ============================================================================
--changeset rbac-base-duplicate-role-grant-exception:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
create or replace procedure raiseDuplicateRoleGrantException(subRoleId uuid, superRoleId uuid)
language plpgsql as $$
declare
subRoleIdName text;
superRoleIdName text;
begin
select roleIdName from rbacRole_ev where uuid=subRoleId into subRoleIdName;
select roleIdName from rbacRole_ev where uuid=superRoleId into superRoleIdName;
raise exception '[400] Duplicate role grant detected: role % (%) already granted to % (%)', subRoleId, subRoleIdName, superRoleId, superRoleIdName;
end;
$$;
--//
-- ============================================================================ -- ============================================================================
--changeset rbac-base-GRANTS:1 endDelimiter:--// --changeset rbac-base-GRANTS:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
@ -634,7 +675,7 @@ begin
perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole'); perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole');
if isGranted(subRoleId, superRoleId) then if isGranted(subRoleId, superRoleId) then
raise exception '[400] Cyclic role grant detected between % and %', subRoleId, superRoleId; call raiseDuplicateRoleGrantException(subRoleId, superRoleId);
end if; end if;
insert insert
@ -650,6 +691,11 @@ declare
superRoleId uuid; superRoleId uuid;
subRoleId uuid; subRoleId uuid;
begin begin
-- FIXME: maybe separate method grantRoleToRoleIfNotNull(...)?
if superRole.objectUuid is null or subRole.objectuuid is null then
return;
end if;
superRoleId := findRoleId(superRole); superRoleId := findRoleId(superRole);
subRoleId := findRoleId(subRole); subRoleId := findRoleId(subRole);
@ -657,7 +703,7 @@ begin
perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole'); perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole');
if isGranted(subRoleId, superRoleId) then if isGranted(subRoleId, superRoleId) then
raise exception '[400] Cyclic role grant detected between % and %', subRoleId, superRoleId; call raiseDuplicateRoleGrantException(subRoleId, superRoleId);
end if; end if;
insert insert
@ -672,6 +718,7 @@ declare
superRoleId uuid; superRoleId uuid;
subRoleId uuid; subRoleId uuid;
begin begin
if ( superRoleId is null ) then return; end if;
superRoleId := findRoleId(superRole); superRoleId := findRoleId(superRole);
if ( subRoleId is null ) then return; end if; if ( subRoleId is null ) then return; end if;
subRoleId := findRoleId(subRole); subRoleId := findRoleId(subRole);
@ -680,7 +727,7 @@ begin
perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole'); perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole');
if isGranted(subRoleId, superRoleId) then if isGranted(subRoleId, superRoleId) then
raise exception '[400] Cyclic role grant detected between % and %', subRoleId, superRoleId; call raiseDuplicateRoleGrantException(subRoleId, superRoleId);
end if; end if;
insert insert
@ -704,11 +751,39 @@ begin
if (isGranted(superRoleId, subRoleId)) then if (isGranted(superRoleId, subRoleId)) then
delete from RbacGrants where ascendantUuid = superRoleId and descendantUuid = subRoleId; delete from RbacGrants where ascendantUuid = superRoleId and descendantUuid = subRoleId;
else else
raise exception 'cannot revoke role % (%) from % (% because it is not granted', raise exception 'cannot revoke role % (%) from % (%) because it is not granted',
subRole, subRoleId, superRole, superRoleId; subRole, subRoleId, superRole, superRoleId;
end if; end if;
end; $$; end; $$;
create or replace procedure revokePermissionFromRole(permissionId UUID, superRole RbacRoleDescriptor)
language plpgsql as $$
declare
superRoleId uuid;
permissionOp text;
objectTable text;
objectUuid uuid;
begin
superRoleId := findRoleId(superRole);
perform assertReferenceType('superRoleId (ascendant)', superRoleId, 'RbacRole');
perform assertReferenceType('permission (descendant)', permissionId, 'RbacPermission');
if (isGranted(superRoleId, permissionId)) then
delete from RbacGrants where ascendantUuid = superRoleId and descendantUuid = permissionId;
else
select p.op, o.objectTable, o.uuid
from rbacGrants g
join rbacPermission p on p.uuid=g.descendantUuid
join rbacobject o on o.uuid=p.objectUuid
where g.uuid=permissionId
into permissionOp, objectTable, objectUuid;
raise exception 'cannot revoke permission % (% on %#% (%) from % (%)) because it is not granted',
permissionId, permissionOp, objectTable, objectUuid, permissionId, superRole, superRoleId;
end if;
end; $$;
-- ============================================================================ -- ============================================================================
--changeset rbac-base-QUERY-ACCESSIBLE-OBJECT-UUIDS:1 endDelimiter:--// --changeset rbac-base-QUERY-ACCESSIBLE-OBJECT-UUIDS:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------

View File

@ -56,14 +56,17 @@ begin
roleTypeToAssume = split_part(roleNameParts, '#', 3); roleTypeToAssume = split_part(roleNameParts, '#', 3);
objectUuidToAssume = findObjectUuidByIdName(objectTableToAssume, objectNameToAssume); objectUuidToAssume = findObjectUuidByIdName(objectTableToAssume, objectNameToAssume);
if objectUuidToAssume is null then
raise exception '[401] object % cannot be found in table %', objectNameToAssume, objectTableToAssume;
end if;
select uuid as roleuuidToAssume select uuid
from RbacRole r from RbacRole r
where r.objectUuid = objectUuidToAssume where r.objectUuid = objectUuidToAssume
and r.roleType = roleTypeToAssume and r.roleType = roleTypeToAssume
into roleUuidToAssume; into roleUuidToAssume;
if roleUuidToAssume is null then if roleUuidToAssume is null then
raise exception '[403] role % not accessible for user %', roleName, currentSubjects(); raise exception '[403] role % does not exist or is not accessible for user %', roleName, currentUser();
end if; end if;
if not isGranted(currentUserUuid, roleUuidToAssume) then if not isGranted(currentUserUuid, roleUuidToAssume) then
raise exception '[403] user % has no permission to assume role %', currentUser(), roleName; raise exception '[403] user % has no permission to assume role %', currentUser(), roleName;

View File

@ -37,7 +37,7 @@ declare
subRoleUuid uuid; subRoleUuid uuid;
superRoleUuid uuid; superRoleUuid uuid;
userUuid uuid; userUuid uuid;
grantedByRoleUuid uuid; userGrantsByRoleUuid uuid;
begin begin
roleUuid := createRole(roleDescriptor); roleUuid := createRole(roleDescriptor);
@ -58,14 +58,15 @@ begin
end loop; end loop;
if cardinality(userUuids) > 0 then if cardinality(userUuids) > 0 then
-- direct grants to users need a grantedByRole which can revoke the grant
if grantedByRole is null then if grantedByRole is null then
grantedByRoleUuid := roleUuid; userGrantsByRoleUuid := roleUuid; -- FIXME: or do we want to require an explicit userGrantsByRoleUuid?
else else
grantedByRoleUuid := getRoleId(grantedByRole); userGrantsByRoleUuid := getRoleId(grantedByRole);
end if; end if;
foreach userUuid in array userUuids foreach userUuid in array userUuids
loop loop
call grantRoleToUserUnchecked(grantedByRoleUuid, roleUuid, userUuid); call grantRoleToUserUnchecked(userGrantsByRoleUuid, roleUuid, userUuid);
end loop; end loop;
end if; end if;

View File

@ -73,6 +73,7 @@ begin
return roleDescriptor('%2$s', entity.uuid, 'tenant', assumed); return roleDescriptor('%2$s', entity.uuid, 'tenant', assumed);
end; $f$; end; $f$;
-- TODO: remove guest role
create or replace function %1$sGuest(entity %2$s, assumed boolean = true) create or replace function %1$sGuest(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor returns RbacRoleDescriptor
language plpgsql language plpgsql
@ -81,6 +82,14 @@ begin
return roleDescriptor('%2$s', entity.uuid, 'guest', assumed); return roleDescriptor('%2$s', entity.uuid, 'guest', assumed);
end; $f$; end; $f$;
create or replace function %1$sReferrer(entity %2$s)
returns RbacRoleDescriptor
language plpgsql
strict as $f$
begin
return roleDescriptor('%2$s', entity.uuid, 'referrer');
end; $f$;
$sql$, prefix, targetTable); $sql$, prefix, targetTable);
execute sql; execute sql;
end; $$; end; $$;
@ -148,12 +157,16 @@ end; $$;
--changeset rbac-generators-RESTRICTED-VIEW:1 endDelimiter:--// --changeset rbac-generators-RESTRICTED-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
create or replace procedure generateRbacRestrictedView(targetTable text, orderBy text, columnUpdates text = null) create or replace procedure generateRbacRestrictedView(targetTable text, orderBy text, columnUpdates text = null, columnNames text = '*')
language plpgsql as $$ language plpgsql as $$
declare declare
sql text; sql text;
newColumns text;
begin begin
targetTable := lower(targetTable); targetTable := lower(targetTable);
if columnNames = '*' then
columnNames := columnsNames(targetTable);
end if;
/* /*
Creates a restricted view based on the 'SELECT' permission of the current subject. Creates a restricted view based on the 'SELECT' permission of the current subject.
@ -175,6 +188,7 @@ begin
/** /**
Instead of insert trigger function for the restricted view. Instead of insert trigger function for the restricted view.
*/ */
newColumns := 'new.' || replace(columnNames, ',', ', new.');
sql := format($sql$ sql := format($sql$
create or replace function %1$sInsert() create or replace function %1$sInsert()
returns trigger returns trigger
@ -183,12 +197,12 @@ begin
newTargetRow %1$s; newTargetRow %1$s;
begin begin
insert insert
into %1$s into %1$s (%2$s)
values (new.*) values (%3$s)
returning * into newTargetRow; returning * into newTargetRow;
return newTargetRow; return newTargetRow;
end; $f$; end; $f$;
$sql$, targetTable); $sql$, targetTable, columnNames, newColumns);
execute sql; execute sql;
/* /*

View File

@ -121,6 +121,29 @@ begin transaction;
call defineContext('creating global admin role', null, null, null); call defineContext('creating global admin role', null, null, null);
select createRole(globalAdmin()); select createRole(globalAdmin());
commit; commit;
--//
-- ============================================================================
--changeset rbac-global-GUEST-ROLE:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
A global guest role.
*/
create or replace function globalGuest(assumed boolean = true)
returns RbacRoleDescriptor
returns null on null input
stable -- leakproof
language sql as $$
select 'global', (select uuid from RbacObject where objectTable = 'global'), 'guest'::RbacRoleType, assumed;
$$;
begin transaction;
call defineContext('creating global guest role', null, null, null);
select createRole(globalGuest());
commit;
--//
-- ============================================================================ -- ============================================================================
--changeset rbac-global-ADMIN-USERS:1 context:dev,tc endDelimiter:--// --changeset rbac-global-ADMIN-USERS:1 context:dev,tc endDelimiter:--//

View File

@ -38,8 +38,6 @@ begin
SELECT * FROM test_package p SELECT * FROM test_package p
WHERE p.uuid= NEW.packageUuid WHERE p.uuid= NEW.packageUuid
INTO newPackage; INTO newPackage;
assert newPackage.uuid is not null, format('newPackage must not be null for NEW.packageUuid = %s', NEW.packageUuid);
perform createRoleWithGrants( perform createRoleWithGrants(
testDomainOwner(NEW), testDomainOwner(NEW),
@ -91,41 +89,12 @@ create or replace procedure updateRbacRulesForTestDomain(
NEW test_domain NEW test_domain
) )
language plpgsql as $$ language plpgsql as $$
declare
oldPackage test_package;
newPackage test_package;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM test_package p
WHERE p.uuid= OLD.packageUuid
INTO oldPackage;
assert oldPackage.uuid is not null, format('oldPackage must not be null for OLD.packageUuid = %s', OLD.packageUuid);
SELECT * FROM test_package p
WHERE p.uuid= NEW.packageUuid
INTO newPackage;
assert newPackage.uuid is not null, format('newPackage must not be null for NEW.packageUuid = %s', NEW.packageUuid);
if NEW.packageUuid <> OLD.packageUuid then
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'INSERT'), testPackageAdmin(oldPackage));
call revokeRoleFromRole(testDomainOwner(OLD), testPackageAdmin(oldPackage));
call grantRoleToRole(testDomainOwner(NEW), testPackageAdmin(newPackage));
call revokeRoleFromRole(testPackageTenant(oldPackage), testDomainOwner(OLD));
call grantRoleToRole(testPackageTenant(newPackage), testDomainOwner(NEW));
call revokeRoleFromRole(testPackageTenant(oldPackage), testDomainAdmin(OLD));
call grantRoleToRole(testPackageTenant(newPackage), testDomainAdmin(NEW));
if NEW.packageUuid is distinct from OLD.packageUuid then
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
call buildRbacSystemForTestDomain(NEW);
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
end; $$; end; $$;
/* /*

View File

@ -38,14 +38,10 @@ begin
call enterTriggerForObjectUuid(NEW.uuid); call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_person as p where p.uuid = NEW.holderUuid INTO newHolderPerson; select * from hs_office_person as p where p.uuid = NEW.holderUuid INTO newHolderPerson;
assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.holderUuid = %s', NEW.holderUuid);
select * from hs_office_person as p where p.uuid = NEW.anchorUuid INTO newAnchorPerson; select * from hs_office_person as p where p.uuid = NEW.anchorUuid INTO newAnchorPerson;
assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.anchorUuid = %s', NEW.anchorUuid);
select * from hs_office_contact as c where c.uuid = NEW.contactUuid INTO newContact; select * from hs_office_contact as c where c.uuid = NEW.contactUuid INTO newContact;
assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid);
perform createRoleWithGrants( perform createRoleWithGrants(
hsOfficeRelationOwner(NEW), hsOfficeRelationOwner(NEW),
@ -73,13 +69,13 @@ begin
hsOfficeRelationTenant(NEW), hsOfficeRelationTenant(NEW),
permissions => array['SELECT'], permissions => array['SELECT'],
incomingSuperRoles => array[ incomingSuperRoles => array[
hsOfficeRelationAgent(NEW),
hsOfficeContactAdmin(newContact), hsOfficeContactAdmin(newContact),
hsOfficeRelationAgent(NEW),
hsOfficePersonAdmin(newHolderPerson)], hsOfficePersonAdmin(newHolderPerson)],
outgoingSubRoles => array[ outgoingSubRoles => array[
hsOfficePersonReferrer(newHolderPerson),
hsOfficeContactReferrer(newContact), hsOfficeContactReferrer(newContact),
hsOfficePersonReferrer(newAnchorPerson)] hsOfficePersonReferrer(newAnchorPerson),
hsOfficePersonReferrer(newHolderPerson)]
); );
call leaveTriggerForObjectUuid(NEW.uuid); call leaveTriggerForObjectUuid(NEW.uuid);
@ -118,48 +114,12 @@ create or replace procedure updateRbacRulesForHsOfficeRelation(
NEW hs_office_relation NEW hs_office_relation
) )
language plpgsql as $$ language plpgsql as $$
declare
oldHolderPerson hs_office_person;
newHolderPerson hs_office_person;
oldAnchorPerson hs_office_person;
newAnchorPerson hs_office_person;
oldContact hs_office_contact;
newContact hs_office_contact;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_person as p where p.uuid = OLD.holderUuid INTO oldHolderPerson;
assert oldHolderPerson.uuid is not null, format('oldHolderPerson must not be null for OLD.holderUuid = %s', OLD.holderUuid);
select * from hs_office_person as p where p.uuid = NEW.holderUuid INTO newHolderPerson;
assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.holderUuid = %s', NEW.holderUuid);
select * from hs_office_person as p where p.uuid = OLD.anchorUuid INTO oldAnchorPerson;
assert oldAnchorPerson.uuid is not null, format('oldAnchorPerson must not be null for OLD.anchorUuid = %s', OLD.anchorUuid);
select * from hs_office_person as p where p.uuid = NEW.anchorUuid INTO newAnchorPerson;
assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.anchorUuid = %s', NEW.anchorUuid);
select * from hs_office_contact as c where c.uuid = OLD.contactUuid INTO oldContact;
assert oldContact.uuid is not null, format('oldContact must not be null for OLD.contactUuid = %s', OLD.contactUuid);
select * from hs_office_contact as c where c.uuid = NEW.contactUuid INTO newContact;
assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid);
if NEW.contactUuid <> OLD.contactUuid then
call revokeRoleFromRole(hsOfficeRelationTenant(OLD), hsOfficeContactAdmin(oldContact));
call grantRoleToRole(hsOfficeRelationTenant(NEW), hsOfficeContactAdmin(newContact));
call revokeRoleFromRole(hsOfficeContactReferrer(oldContact), hsOfficeRelationTenant(OLD));
call grantRoleToRole(hsOfficeContactReferrer(newContact), hsOfficeRelationTenant(NEW));
if NEW.contactUuid is distinct from OLD.contactUuid then
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
call buildRbacSystemForHsOfficeRelation(NEW);
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
end; $$; end; $$;
/* /*

View File

@ -57,8 +57,8 @@ begin
hsOfficeSepaMandateAgent(NEW), hsOfficeSepaMandateAgent(NEW),
incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW)], incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW)],
outgoingSubRoles => array[ outgoingSubRoles => array[
hsOfficeBankAccountReferrer(newBankAccount), hsOfficeRelationAgent(newDebitorRel),
hsOfficeRelationAgent(newDebitorRel)] hsOfficeBankAccountReferrer(newBankAccount)]
); );
perform createRoleWithGrants( perform createRoleWithGrants(

View File

@ -41,7 +41,6 @@ begin
FROM hs_office_relation AS partnerRel FROM hs_office_relation AS partnerRel
WHERE ${debitorRel}.anchorUuid = partnerRel.holderUuid WHERE ${debitorRel}.anchorUuid = partnerRel.holderUuid
INTO newPartnerRel; INTO newPartnerRel;
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid);
SELECT * SELECT *
FROM hs_office_relation AS r FROM hs_office_relation AS r
@ -53,7 +52,6 @@ begin
FROM hs_office_relation AS r FROM hs_office_relation AS r
WHERE r.type = 'DEBITOR' AND r.holderUuid = NEW.debitorRelUuid WHERE r.type = 'DEBITOR' AND r.holderUuid = NEW.debitorRelUuid
INTO newRefundBankAccount; INTO newRefundBankAccount;
assert newRefundBankAccount.uuid is not null, format('newRefundBankAccount must not be null for NEW.refundBankAccountUuid = %s', NEW.refundBankAccountUuid);
call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationAgent(newDebitorRel)); call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationAgent(newDebitorRel));
call grantRoleToRole(hsOfficeRelationAdmin(newDebitorRel), hsOfficeRelationAdmin(newPartnerRel)); call grantRoleToRole(hsOfficeRelationAdmin(newDebitorRel), hsOfficeRelationAdmin(newPartnerRel));
@ -101,66 +99,12 @@ create or replace procedure updateRbacRulesForHsOfficeDebitor(
NEW hs_office_debitor NEW hs_office_debitor
) )
language plpgsql as $$ language plpgsql as $$
declare
oldPartnerRel hs_office_relation;
newPartnerRel hs_office_relation;
oldDebitorRel hs_office_relation;
newDebitorRel hs_office_relation;
oldRefundBankAccount hs_office_bankaccount;
newRefundBankAccount hs_office_bankaccount;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
SELECT *
FROM hs_office_relation AS partnerRel
WHERE ${debitorRel}.anchorUuid = partnerRel.holderUuid
INTO oldPartnerRel;
assert oldPartnerRel.uuid is not null, format('oldPartnerRel must not be null for OLD.partnerRelUuid = %s', OLD.partnerRelUuid);
SELECT *
FROM hs_office_relation AS partnerRel
WHERE ${debitorRel}.anchorUuid = partnerRel.holderUuid
INTO newPartnerRel;
assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid);
SELECT *
FROM hs_office_relation AS r
WHERE r.type = 'DEBITOR' AND r.holderUuid = OLD.debitorRelUuid
INTO oldDebitorRel;
assert oldDebitorRel.uuid is not null, format('oldDebitorRel must not be null for OLD.debitorRelUuid = %s', OLD.debitorRelUuid);
SELECT *
FROM hs_office_relation AS r
WHERE r.type = 'DEBITOR' AND r.holderUuid = NEW.debitorRelUuid
INTO newDebitorRel;
assert newDebitorRel.uuid is not null, format('newDebitorRel must not be null for NEW.debitorRelUuid = %s', NEW.debitorRelUuid);
SELECT *
FROM hs_office_relation AS r
WHERE r.type = 'DEBITOR' AND r.holderUuid = OLD.debitorRelUuid
INTO oldRefundBankAccount;
assert oldRefundBankAccount.uuid is not null, format('oldRefundBankAccount must not be null for OLD.refundBankAccountUuid = %s', OLD.refundBankAccountUuid);
SELECT *
FROM hs_office_relation AS r
WHERE r.type = 'DEBITOR' AND r.holderUuid = NEW.debitorRelUuid
INTO newRefundBankAccount;
assert newRefundBankAccount.uuid is not null, format('newRefundBankAccount must not be null for NEW.refundBankAccountUuid = %s', NEW.refundBankAccountUuid);
if NEW.refundBankAccountUuid <> OLD.refundBankAccountUuid then
call revokeRoleFromRole(hsOfficeRelationAgent(oldDebitorRel), hsOfficeBankAccountAdmin(oldRefundBankAccount));
call grantRoleToRole(hsOfficeRelationAgent(newDebitorRel), hsOfficeBankAccountAdmin(newRefundBankAccount));
call revokeRoleFromRole(hsOfficeBankAccountReferrer(oldRefundBankAccount), hsOfficeRelationAgent(oldDebitorRel));
call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationAgent(newDebitorRel));
if NEW.refundBankAccountUuid is distinct from OLD.refundBankAccountUuid then
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
call buildRbacSystemForHsOfficeDebitor(NEW);
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
end; $$; end; $$;
/* /*

View File

@ -11,6 +11,8 @@ databaseChangeLog:
file: db/changelog/005-uuid-ossp-extension.sql file: db/changelog/005-uuid-ossp-extension.sql
- include: - include:
file: db/changelog/006-numeric-hash-functions.sql file: db/changelog/006-numeric-hash-functions.sql
- include:
file: db/changelog/007-table-columns.sql
- include: - include:
file: db/changelog/009-check-environment.sql file: db/changelog/009-check-environment.sql
- include: - include: