diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantController.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantController.java index 29bdc2d8..9dfaea74 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantController.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantController.java @@ -94,4 +94,17 @@ public class RbacGrantController implements RbacGrantsApi { 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 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); +// } + } diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleType.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleType.java index 153344fa..fa5b16aa 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleType.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacrole/RbacRoleType.java @@ -1,5 +1,5 @@ package net.hostsharing.hsadminng.rbac.rbacrole; public enum RbacRoleType { - owner, admin, agent, tenant, guest + owner, admin, agent, tenant, guest, referrer } diff --git a/src/main/resources/db/changelog/007-table-columns.sql b/src/main/resources/db/changelog/007-table-columns.sql new file mode 100644 index 00000000..588defba --- /dev/null +++ b/src/main/resources/db/changelog/007-table-columns.sql @@ -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; $$ +--// diff --git a/src/main/resources/db/changelog/050-rbac-base.sql b/src/main/resources/db/changelog/050-rbac-base.sql index 0c64866c..735f1932 100644 --- a/src/main/resources/db/changelog/050-rbac-base.sql +++ b/src/main/resources/db/changelog/050-rbac-base.sql @@ -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 ( @@ -373,10 +373,12 @@ create table RbacPermission uuid uuid primary key references RbacReference (uuid) on delete cascade, objectUuid uuid not null references RbacObject, op RbacOp not null, - opTableName varchar(60), - unique (objectUuid, op) + opTableName varchar(60) ); +ALTER TABLE RbacPermission + ADD CONSTRAINT RbacPermission_uc UNIQUE NULLS NOT DISTINCT (objectUuid, op, opTableName); + call create_journal('RbacPermission'); 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 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 insert into RbacReference ("type") values ('RbacPermission') @@ -466,8 +471,44 @@ select uuid and p.op = forOp 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:--// -- ---------------------------------------------------------------------------- @@ -634,7 +675,7 @@ begin perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole'); if isGranted(subRoleId, superRoleId) then - raise exception '[400] Cyclic role grant detected between % and %', subRoleId, superRoleId; + call raiseDuplicateRoleGrantException(subRoleId, superRoleId); end if; insert @@ -650,6 +691,11 @@ declare superRoleId uuid; subRoleId uuid; begin + -- FIXME: maybe separate method grantRoleToRoleIfNotNull(...)? + if superRole.objectUuid is null or subRole.objectuuid is null then + return; + end if; + superRoleId := findRoleId(superRole); subRoleId := findRoleId(subRole); @@ -657,7 +703,7 @@ begin perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole'); if isGranted(subRoleId, superRoleId) then - raise exception '[400] Cyclic role grant detected between % and %', subRoleId, superRoleId; + call raiseDuplicateRoleGrantException(subRoleId, superRoleId); end if; insert @@ -672,6 +718,7 @@ declare superRoleId uuid; subRoleId uuid; begin + if ( superRoleId is null ) then return; end if; superRoleId := findRoleId(superRole); if ( subRoleId is null ) then return; end if; subRoleId := findRoleId(subRole); @@ -680,7 +727,7 @@ begin perform assertReferenceType('subRoleId (descendant)', subRoleId, 'RbacRole'); if isGranted(subRoleId, superRoleId) then - raise exception '[400] Cyclic role grant detected between % and %', subRoleId, superRoleId; + call raiseDuplicateRoleGrantException(subRoleId, superRoleId); end if; insert @@ -704,11 +751,39 @@ begin if (isGranted(superRoleId, subRoleId)) then delete from RbacGrants where ascendantUuid = superRoleId and descendantUuid = subRoleId; 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; end if; 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:--// -- ---------------------------------------------------------------------------- diff --git a/src/main/resources/db/changelog/054-rbac-context.sql b/src/main/resources/db/changelog/054-rbac-context.sql index ede86057..5437131f 100644 --- a/src/main/resources/db/changelog/054-rbac-context.sql +++ b/src/main/resources/db/changelog/054-rbac-context.sql @@ -56,14 +56,17 @@ begin roleTypeToAssume = split_part(roleNameParts, '#', 3); 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 where r.objectUuid = objectUuidToAssume and r.roleType = roleTypeToAssume into roleUuidToAssume; 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; if not isGranted(currentUserUuid, roleUuidToAssume) then raise exception '[403] user % has no permission to assume role %', currentUser(), roleName; diff --git a/src/main/resources/db/changelog/057-rbac-role-builder.sql b/src/main/resources/db/changelog/057-rbac-role-builder.sql index 1a7da953..b3ddbecd 100644 --- a/src/main/resources/db/changelog/057-rbac-role-builder.sql +++ b/src/main/resources/db/changelog/057-rbac-role-builder.sql @@ -31,13 +31,13 @@ create or replace function createRoleWithGrants( called on null input language plpgsql as $$ declare - roleUuid uuid; - subRoleDesc RbacRoleDescriptor; - superRoleDesc RbacRoleDescriptor; - subRoleUuid uuid; - superRoleUuid uuid; - userUuid uuid; - grantedByRoleUuid uuid; + roleUuid uuid; + subRoleDesc RbacRoleDescriptor; + superRoleDesc RbacRoleDescriptor; + subRoleUuid uuid; + superRoleUuid uuid; + userUuid uuid; + userGrantsByRoleUuid uuid; begin roleUuid := createRole(roleDescriptor); @@ -58,14 +58,15 @@ begin end loop; if cardinality(userUuids) > 0 then + -- direct grants to users need a grantedByRole which can revoke the grant if grantedByRole is null then - grantedByRoleUuid := roleUuid; + userGrantsByRoleUuid := roleUuid; -- FIXME: or do we want to require an explicit userGrantsByRoleUuid? else - grantedByRoleUuid := getRoleId(grantedByRole); + userGrantsByRoleUuid := getRoleId(grantedByRole); end if; foreach userUuid in array userUuids loop - call grantRoleToUserUnchecked(grantedByRoleUuid, roleUuid, userUuid); + call grantRoleToUserUnchecked(userGrantsByRoleUuid, roleUuid, userUuid); end loop; end if; diff --git a/src/main/resources/db/changelog/058-rbac-generators.sql b/src/main/resources/db/changelog/058-rbac-generators.sql index 89d585ea..efe71b1b 100644 --- a/src/main/resources/db/changelog/058-rbac-generators.sql +++ b/src/main/resources/db/changelog/058-rbac-generators.sql @@ -73,6 +73,7 @@ begin return roleDescriptor('%2$s', entity.uuid, 'tenant', assumed); end; $f$; + -- TODO: remove guest role create or replace function %1$sGuest(entity %2$s, assumed boolean = true) returns RbacRoleDescriptor language plpgsql @@ -81,6 +82,14 @@ begin return roleDescriptor('%2$s', entity.uuid, 'guest', assumed); 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); execute sql; end; $$; @@ -148,12 +157,16 @@ end; $$; --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 $$ declare sql text; + newColumns text; begin targetTable := lower(targetTable); + if columnNames = '*' then + columnNames := columnsNames(targetTable); + end if; /* Creates a restricted view based on the 'SELECT' permission of the current subject. @@ -175,20 +188,21 @@ begin /** Instead of insert trigger function for the restricted view. */ + newColumns := 'new.' || replace(columnNames, ',', ', new.'); sql := format($sql$ - create or replace function %1$sInsert() - returns trigger - language plpgsql as $f$ - declare - newTargetRow %1$s; - begin - insert - into %1$s - values (new.*) - returning * into newTargetRow; - return newTargetRow; - end; $f$; - $sql$, targetTable); + create or replace function %1$sInsert() + returns trigger + language plpgsql as $f$ + declare + newTargetRow %1$s; + begin + insert + into %1$s (%2$s) + values (%3$s) + returning * into newTargetRow; + return newTargetRow; + end; $f$; + $sql$, targetTable, columnNames, newColumns); execute sql; /* diff --git a/src/main/resources/db/changelog/080-rbac-global.sql b/src/main/resources/db/changelog/080-rbac-global.sql index 8313d05d..f8058113 100644 --- a/src/main/resources/db/changelog/080-rbac-global.sql +++ b/src/main/resources/db/changelog/080-rbac-global.sql @@ -118,9 +118,32 @@ select 'global', (select uuid from RbacObject where objectTable = 'global'), 'ad $$; begin transaction; -call defineContext('creating global admin role', null, null, null); -select createRole(globalAdmin()); + call defineContext('creating global admin role', null, null, null); + select createRole(globalAdmin()); 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:--// diff --git a/src/main/resources/db/changelog/133-test-domain-rbac.sql b/src/main/resources/db/changelog/133-test-domain-rbac.sql index 6344e43d..e20f21c4 100644 --- a/src/main/resources/db/changelog/133-test-domain-rbac.sql +++ b/src/main/resources/db/changelog/133-test-domain-rbac.sql @@ -38,8 +38,6 @@ begin 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); - perform createRoleWithGrants( testDomainOwner(NEW), @@ -91,41 +89,12 @@ create or replace procedure updateRbacRulesForTestDomain( NEW test_domain ) language plpgsql as $$ - -declare - oldPackage test_package; - newPackage test_package; - 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; - - call leaveTriggerForObjectUuid(NEW.uuid); end; $$; /* diff --git a/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.sql b/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.sql index 9a1f7d1b..65645895 100644 --- a/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.sql +++ b/src/main/resources/db/changelog/223-hs-office-relation-rbac-generated.sql @@ -38,14 +38,10 @@ begin call enterTriggerForObjectUuid(NEW.uuid); 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; - 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; - assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid); - perform createRoleWithGrants( hsOfficeRelationOwner(NEW), @@ -73,13 +69,13 @@ begin hsOfficeRelationTenant(NEW), permissions => array['SELECT'], incomingSuperRoles => array[ - hsOfficeRelationAgent(NEW), hsOfficeContactAdmin(newContact), + hsOfficeRelationAgent(NEW), hsOfficePersonAdmin(newHolderPerson)], outgoingSubRoles => array[ - hsOfficePersonReferrer(newHolderPerson), hsOfficeContactReferrer(newContact), - hsOfficePersonReferrer(newAnchorPerson)] + hsOfficePersonReferrer(newAnchorPerson), + hsOfficePersonReferrer(newHolderPerson)] ); call leaveTriggerForObjectUuid(NEW.uuid); @@ -118,48 +114,12 @@ create or replace procedure updateRbacRulesForHsOfficeRelation( NEW hs_office_relation ) 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 - 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; - - call leaveTriggerForObjectUuid(NEW.uuid); end; $$; /* diff --git a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.sql b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.sql index f0718272..ac4e9fee 100644 --- a/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.sql +++ b/src/main/resources/db/changelog/253-hs-office-sepamandate-rbac-generated.sql @@ -57,8 +57,8 @@ begin hsOfficeSepaMandateAgent(NEW), incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW)], outgoingSubRoles => array[ - hsOfficeBankAccountReferrer(newBankAccount), - hsOfficeRelationAgent(newDebitorRel)] + hsOfficeRelationAgent(newDebitorRel), + hsOfficeBankAccountReferrer(newBankAccount)] ); perform createRoleWithGrants( diff --git a/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.sql b/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.sql index 760f1fe9..7f6afc13 100644 --- a/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.sql +++ b/src/main/resources/db/changelog/273-hs-office-debitor-rbac-generated.sql @@ -41,7 +41,6 @@ begin 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 @@ -53,7 +52,6 @@ begin 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); call grantRoleToRole(hsOfficeBankAccountReferrer(newRefundBankAccount), hsOfficeRelationAgent(newDebitorRel)); call grantRoleToRole(hsOfficeRelationAdmin(newDebitorRel), hsOfficeRelationAdmin(newPartnerRel)); @@ -101,66 +99,12 @@ create or replace procedure updateRbacRulesForHsOfficeDebitor( NEW hs_office_debitor ) 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 - 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; - - call leaveTriggerForObjectUuid(NEW.uuid); end; $$; /* diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 5934c9a4..6047befa 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -11,6 +11,8 @@ databaseChangeLog: file: db/changelog/005-uuid-ossp-extension.sql - include: file: db/changelog/006-numeric-hash-functions.sql + - include: + file: db/changelog/007-table-columns.sql - include: file: db/changelog/009-check-environment.sql - include: