diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountEntity.java index f8409ffd..664ed8fe 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountEntity.java @@ -62,7 +62,7 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable { .withIdentityView(SQL.projection("iban")) .withUpdatableColumns("holder", "iban", "bic") - .toRole("global", GUEST).grantPermission("bankAccount", INSERT) + .toRole("global", GUEST).grantPermission(INSERT) .createRole(OWNER, (with) -> { with.owningUser(CREATOR); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactEntity.java index e2ff6b3d..62f5316a 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactEntity.java @@ -76,7 +76,7 @@ public class HsOfficeContactEntity implements Stringifyable, HasUuid { .createSubRole(REFERRER, (with) -> { with.permission(SELECT); }) - .toRole(GLOBAL, GUEST).grantPermission("contact", INSERT); + .toRole(GLOBAL, GUEST).grantPermission(INSERT); } public static void main(String[] args) throws IOException { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntity.java index 1b2045e9..0f1e4d54 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntity.java @@ -6,7 +6,6 @@ import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; -import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity; import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL; @@ -130,7 +129,7 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable { "vatBusiness", "vatReverseCharge", "defaultPrefix" /* TODO: do we want that updatable? */) - .toRole("global", ADMIN).grantPermission("debitor", INSERT) + .toRole("global", ADMIN).grantPermission(INSERT) .importRootEntityAliasProxy("debitorRel", HsOfficeRelationshipEntity.class, fetchedBySql(""" diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java index 5afcd2c8..205a1e5b 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java @@ -136,7 +136,7 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable { JOIN hs_office_relationship AS r ON r.uuid = p.partnerRoleUuid WHERE p.uuid = ${REF}.partnerUuid """)) - .toRole("partnerRel", ADMIN).grantPermission("membership", INSERT) + .toRole("partnerRel", ADMIN).grantPermission(INSERT) .createRole(OWNER, (with) -> { with.owningUser(CREATOR); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntity.java index 6376e7db..7bb4aea3 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerDetailsEntity.java @@ -81,7 +81,7 @@ public class HsOfficePartnerDetailsEntity implements HasUuid, Stringifyable { "birthName", "birthday", "dateOfDeath") - .toRole("global", ADMIN).grantPermission("partnerDetails", INSERT) + .toRole("global", ADMIN).grantPermission(INSERT) // The grants are defined in HsOfficePartnerEntity.rbac() // because they have to be changed when its partnerRel changes, diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntity.java index feec5510..3eaf03a3 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntity.java @@ -25,7 +25,6 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import jakarta.persistence.*; import java.io.IOException; import java.util.UUID; @@ -96,7 +95,7 @@ public class HsOfficePartnerEntity implements Stringifyable, HasUuid { return rbacViewFor("partner", HsOfficePartnerEntity.class) .withIdentityView(SQL.projection("'P-' || partnerNumber")) .withUpdatableColumns("partnerroleuuid") - .toRole("global", ADMIN).grantPermission("partner", INSERT) // FIXME: global -> partnerRel.relAnchor? + .toRole("global", ADMIN).grantPermission(INSERT) // FIXME: global -> partnerRel.relAnchor? .importRootEntityAliasProxy("partnerRel", HsOfficeRelationshipEntity.class, fetchedBySql("SELECT * FROM hs_office_relationship AS r WHERE r.uuid = ${ref}.partnerRoleUuid"), diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java index 1a22c169..86ef8145 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java @@ -81,7 +81,7 @@ public class HsOfficePersonEntity implements HasUuid, Stringifyable { return rbacViewFor("person", HsOfficePersonEntity.class) .withIdentityView(SQL.projection("concat(tradeName, familyName, givenName)")) .withUpdatableColumns("personType", "tradeName", "givenName", "familyName") - .toRole("global", GUEST).grantPermission("person", INSERT) + .toRole("global", GUEST).grantPermission(INSERT) .createRole(OWNER, (with) -> { with.permission(DELETE); diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java index 02c96ad1..0b785617 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java @@ -136,7 +136,7 @@ public class HsOfficeSepaMandateEntity implements Stringifyable, HasUuid { with.permission(SELECT); }) - .toRole("debitorRel", ADMIN).grantPermission("sepaMandate", INSERT); + .toRole("debitorRel", ADMIN).grantPermission(INSERT); } public static void main(String[] args) throws IOException { diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java index a42bbbe8..491d1d67 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java @@ -289,11 +289,9 @@ public class RbacView { return RbacView.this; } - // TODO: switch order or parameters for more natural readability - public RbacView grantPermission(final String entityAliasName, final Permission perm) { - final var entityAlias = findEntityAlias(entityAliasName); - final var forTable = entityAlias.getRawTableName(); - findOrCreateGrantDef(findRbacPerm(entityAlias, perm, forTable), superRoleDef).toCreate(); + public RbacView grantPermission(final Permission perm) { + final var forTable = rootEntityAlias.getRawTableName(); + findOrCreateGrantDef(findRbacPerm(rootEntityAlias, perm, forTable), superRoleDef).toCreate(); return RbacView.this; } diff --git a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntity.java b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntity.java index f0a0827c..b4152fa9 100644 --- a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerEntity.java @@ -41,7 +41,7 @@ public class TestCustomerEntity implements HasUuid { .withIdentityView(SQL.projection("prefix")) .withRestrictedViewOrderBy(SQL.expression("reference")) .withUpdatableColumns("reference", "prefix", "adminUserName") - .toRole("global", ADMIN).grantPermission("customer", INSERT) + .toRole("global", ADMIN).grantPermission(INSERT) .createRole(OWNER, (with) -> { with.owningUser(CREATOR).unassumed(); diff --git a/src/main/java/net/hostsharing/hsadminng/test/dom/TestDomainEntity.java b/src/main/java/net/hostsharing/hsadminng/test/dom/TestDomainEntity.java index 6a031df7..fe053f1f 100644 --- a/src/main/java/net/hostsharing/hsadminng/test/dom/TestDomainEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/test/dom/TestDomainEntity.java @@ -53,7 +53,7 @@ public class TestDomainEntity implements HasUuid { SELECT * FROM test_package p WHERE p.uuid= ${ref}.packageUuid """)) - .toRole("package", ADMIN).grantPermission("domain", INSERT) + .toRole("package", ADMIN).grantPermission(INSERT) .createRole(OWNER, (with) -> { with.incomingSuperRole("package", ADMIN); diff --git a/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageEntity.java b/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageEntity.java index 757fcf05..9dc0d5d9 100644 --- a/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageEntity.java @@ -54,7 +54,7 @@ public class TestPackageEntity implements HasUuid { SELECT * FROM test_customer c WHERE c.uuid= ${ref}.customerUuid """)) - .toRole("customer", ADMIN).grantPermission("package", INSERT) + .toRole("customer", ADMIN).grantPermission(INSERT) .createRole(OWNER, (with) -> { with.incomingSuperRole("customer", ADMIN); diff --git a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.md b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.md index c97e3274..e971fda2 100644 --- a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.md +++ b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.md @@ -1,74 +1,100 @@ -### hs_office_relationship RBAC +### rbac relationship + +This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-15T15:30:23.331560468. ```mermaid - +%%{init:{'flowchart':{'htmlLabels':false}}}%% flowchart TB -subgraph global - style global fill:#eee - - role:global.admin[global.admin] -end - -subgraph contact +subgraph holderPerson["`**holderPerson**`"] direction TB - style contact fill:#eee - - role:contact.owner[contact.admin] - --> role:contact.admin[contact.admin] - --> role:contact.referrer[contact.referrer] + style holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph holderPerson:roles[ ] + style holderPerson:roles fill:#99bcdb,stroke:white + + role:holderPerson:owner[[holderPerson:owner]] + role:holderPerson:admin[[holderPerson:admin]] + role:holderPerson:referrer[[holderPerson:referrer]] + end end -subgraph anchorPerson +subgraph anchorPerson["`**anchorPerson**`"] direction TB - style anchorPerson fill:#eee - - role:anchorPerson.owner[anchorPerson.owner] - --> role:anchorPerson.admin[anchorPerson.admin] - --> role:anchorPerson.referrer[anchorPerson.referrer] + style anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph anchorPerson:roles[ ] + style anchorPerson:roles fill:#99bcdb,stroke:white + + role:anchorPerson:owner[[anchorPerson:owner]] + role:anchorPerson:admin[[anchorPerson:admin]] + role:anchorPerson:referrer[[anchorPerson:referrer]] + end end -subgraph holderPerson +subgraph contact["`**contact**`"] direction TB - style holderPerson fill:#eee - - role:holderPerson.owner[holderPerson.owner] - --> role:holderPerson.admin[holderPerson.admin] - --> role:holderPerson.referrer[holderPerson.referrer] + style contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph contact:roles[ ] + style contact:roles fill:#99bcdb,stroke:white + + role:contact:owner[[contact:owner]] + role:contact:admin[[contact:admin]] + role:contact:referrer[[contact:referrer]] + end end -subgraph relationship +subgraph relationship["`**relationship**`"] + direction TB + style relationship fill:#dd4901,stroke:#274d6e,stroke-width:8px - role:relationship.owner[relationship.owner] - %% permissions - role:relationship.owner --> perm:relationship.*{{relationship.*}} - %% incoming - role:global.admin ---> role:relationship.owner - - role:relationship.admin[relationship.admin] - %% permissions - role:relationship.admin --> perm:relationship.edit{{relationship.edit}} - %% incoming - role:relationship.owner --> role:relationship.admin - role:anchorPerson.admin --> role:relationship.admin - - role:relationship.agent[relationship.agent] - %% incoming - role:relationship.admin --> role:relationship.agent - role:holderPerson.admin --> role:relationship.agent - role:contact.admin --> role:relationship.agent + subgraph relationship:roles[ ] + style relationship:roles fill:#dd4901,stroke:white - role:relationship.tenant[relationship.tenant] - %% permissions - role:relationship.tenant --> perm:relationship.view{{relationship.view}} - %% incoming - role:relationship.agent --> role:relationship.tenant - %% outgoing - role:relationship.tenant --> role:anchorPerson.referrer - role:relationship.tenant --> role:holderPerson.referrer - role:relationship.tenant --> role:contact.referrer - - %% additional - role:anchorPerson.admin =="if REPRESENTATIVE"==> role:holderPerson.admin + role:relationship:owner[[relationship:owner]] + role:relationship:admin[[relationship:admin]] + role:relationship:agent[[relationship:agent]] + role:relationship:tenant[[relationship:tenant]] + end + + subgraph relationship:permissions[ ] + style relationship:permissions fill:#dd4901,stroke:white + + perm:relationship:DELETE{{relationship:DELETE}} + perm:relationship:UPDATE{{relationship:UPDATE}} + perm:relationship:SELECT{{relationship:SELECT}} + end end + +%% granting roles to users +user:creator ==> role:relationship:owner + +%% granting roles to roles +role:global:admin -.-> role:anchorPerson:owner +role:anchorPerson:owner -.-> role:anchorPerson:admin +role:anchorPerson:admin -.-> role:anchorPerson:referrer +role:global:admin -.-> role:holderPerson:owner +role:holderPerson:owner -.-> role:holderPerson:admin +role:holderPerson:admin -.-> role:holderPerson:referrer +role:global:admin -.-> role:contact:owner +role:contact:owner -.-> role:contact:admin +role:contact:admin -.-> role:contact:referrer +role:global:admin ==> role:relationship:owner +role:relationship:owner ==> role:relationship:admin +role:anchorPerson:admin ==> role:relationship:admin +role:relationship:admin ==> role:relationship:agent +role:holderPerson:admin ==> role:relationship:agent +role:relationship:agent ==> role:relationship:tenant +role:holderPerson:admin ==> role:relationship:tenant +role:contact:admin ==> role:relationship:tenant +role:relationship:tenant ==> role:anchorPerson:referrer +role:relationship:tenant ==> role:holderPerson:referrer +role:relationship:tenant ==> role:contact:referrer + +%% granting permissions to roles +role:relationship:owner ==> perm:relationship:DELETE +role:relationship:admin ==> perm:relationship:UPDATE +role:relationship:tenant ==> perm:relationship:SELECT + ``` diff --git a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql index 27e02ee3..1b394457 100644 --- a/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql +++ b/src/main/resources/db/changelog/223-hs-office-relationship-rbac.sql @@ -1,4 +1,6 @@ --liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator at 2024-03-15T15:30:23.341470108. + -- ============================================================================ --changeset hs-office-relationship-rbac-OBJECT:1 endDelimiter:--// @@ -15,184 +17,206 @@ call generateRbacRoleDescriptors('hsOfficeRelationship', 'hs_office_relationship -- ============================================================================ ---changeset hs-office-relationship-rbac-ROLES-CREATION:1 endDelimiter:--// +--changeset hs-office-relationship-rbac-insert-trigger:1 endDelimiter:--// -- ---------------------------------------------------------------------------- /* - Creates and updates the roles and their assignments for relationship entities. + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. */ -create or replace function hsOfficeRelationshipRbacRolesTrigger() - returns trigger - language plpgsql - strict as $$ +create or replace procedure buildRbacSystemForHsOfficeRelationship( + NEW hs_office_relationship +) + language plpgsql as $$ + declare - newAnchorPerson hs_office_person; - newHolderPerson hs_office_person; - oldContact hs_office_contact; - newContact hs_office_contact; + newHolderPerson hs_office_person; + newAnchorPerson hs_office_person; + newContact hs_office_contact; + begin call enterTriggerForObjectUuid(NEW.uuid); - select * from hs_office_person as p where p.uuid = NEW.relAnchorUuid into newAnchorPerson; - select * from hs_office_person as p where p.uuid = NEW.relHolderUuid into newHolderPerson; - select * from hs_office_contact as c where c.uuid = NEW.contactUuid into newContact; + select * from hs_office_person as p where p.uuid = NEW.relHolderUuid INTO newHolderPerson; + assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.relHolderUuid = %s', NEW.relHolderUuid); - if TG_OP = 'INSERT' then + select * from hs_office_person as p where p.uuid = NEW.relAnchorUuid INTO newAnchorPerson; + assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.relAnchorUuid = %s', NEW.relAnchorUuid); - -- cannot be generated using `tools/generate` because there are multiple grants to the same entity type + 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( - hsOfficeRelationshipOwner(NEW), - permissions => array['DELETE'], - incomingSuperRoles => array[ - globalAdmin() - ] - ); - perform createRoleWithGrants( - hsOfficeRelationshipAdmin(NEW), - permissions => array['UPDATE'], - incomingSuperRoles => array[ - hsOfficeRelationshipOwner(NEW), - hsOfficePersonAdmin(newAnchorPerson) - ] - ); + perform createRoleWithGrants( + hsOfficeRelationshipOwner(NEW), + permissions => array['DELETE'], + incomingSuperRoles => array[globalAdmin()], + userUuids => array[currentUserUuid()] + ); - perform createRoleWithGrants( - hsOfficeRelationshipAgent(NEW), - incomingSuperRoles => array[ - hsOfficeRelationshipAdmin(NEW), - hsOfficePersonAdmin(newHolderPerson), - hsOfficeContactAdmin(newContact) - ] - ); + perform createRoleWithGrants( + hsOfficeRelationshipAdmin(NEW), + permissions => array['UPDATE'], + incomingSuperRoles => array[ + hsOfficeRelationshipOwner(NEW), + hsOfficePersonAdmin(newAnchorPerson)] + ); - perform createRoleWithGrants( - hsOfficeRelationshipTenant(NEW), - permissions => array['SELECT'], - incomingSuperRoles => array[ - hsOfficeRelationshipAgent(NEW) - ], - outgoingSubRoles => array[ - hsOfficePersonReferrer(newAnchorPerson), - hsOfficePersonReferrer(newHolderPerson), - hsOfficeContactReferrer(newContact) - ] - ); + perform createRoleWithGrants( + hsOfficeRelationshipAgent(NEW), + incomingSuperRoles => array[ + hsOfficePersonAdmin(newHolderPerson), + hsOfficeRelationshipAdmin(NEW)] + ); - if ( NEW.relType = 'REPRESENTATIVE' ) then - call grantRoleToRole(hsOfficePersonAdmin(newHolderPerson), hsOfficePersonAdmin(newAnchorPerson)); - end if; - - elsif TG_OP = 'UPDATE' then - - if OLD.contactUuid <> NEW.contactUuid then - -- only the contact can be updated, - -- in other cases, a new relationship needs to be created and the old updated - - select * from hs_office_contact as c where c.uuid = OLD.contactUuid into oldContact; - - call revokeRoleFromRole( hsOfficeContactReferrer(oldContact), hsOfficeRelationshipTenant(NEW) ); - call grantRoleToRole( hsOfficeContactReferrer(newContact), hsOfficeRelationshipTenant(NEW) ); - - call revokeRoleFromRole( hsOfficeRelationshipAgent(NEW), hsOfficeContactAdmin(oldContact) ); - call grantRoleToRole( hsOfficeRelationshipAgent(NEW), hsOfficeContactAdmin(newContact) ); - end if; - else - raise exception 'invalid usage of TRIGGER'; - end if; + perform createRoleWithGrants( + hsOfficeRelationshipTenant(NEW), + permissions => array['SELECT'], + incomingSuperRoles => array[ + hsOfficeRelationshipAgent(NEW), + hsOfficeContactAdmin(newContact), + hsOfficePersonAdmin(newHolderPerson)], + outgoingSubRoles => array[ + hsOfficeContactReferrer(newContact), + hsOfficePersonReferrer(newHolderPerson), + hsOfficePersonReferrer(newAnchorPerson)] + ); call leaveTriggerForObjectUuid(NEW.uuid); - return NEW; end; $$; /* - An AFTER INSERT TRIGGER which creates the role structure for a new customer. + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_relationship row. */ -create trigger createRbacRolesForHsOfficeRelationship_Trigger - after insert - on hs_office_relationship - for each row -execute procedure hsOfficeRelationshipRbacRolesTrigger(); -/* - An AFTER UPDATE TRIGGER which updates the role structure of a customer. - */ -create trigger updateRbacRolesForHsOfficeRelationship_Trigger - after update - on hs_office_relationship +create or replace function insertTriggerForHsOfficeRelationship_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficeRelationship(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficeRelationship_tg + after insert on hs_office_relationship for each row -execute procedure hsOfficeRelationshipRbacRolesTrigger(); +execute procedure insertTriggerForHsOfficeRelationship_tf(); --// -- ============================================================================ ---changeset hs-office-relationship-rbac-IDENTITY-VIEW:1 endDelimiter:--// +--changeset hs-office-relationship-rbac-update-trigger:1 endDelimiter:--// -- ---------------------------------------------------------------------------- -call generateRbacIdentityViewFromProjection('hs_office_relationship', $idName$ - (select idName from hs_office_person_iv p where p.uuid = target.relAnchorUuid) - || '-with-' || target.relType || '-' || - (select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid) - $idName$); + +/* + Called from the AFTER UPDATE TRIGGER to re-wire the grants. + */ + +create or replace procedure updateRbacRulesForHsOfficeRelationship( + OLD hs_office_relationship, + NEW hs_office_relationship +) + 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.relHolderUuid INTO oldHolderPerson; + assert oldHolderPerson.uuid is not null, format('oldHolderPerson must not be null for OLD.relHolderUuid = %s', OLD.relHolderUuid); + + select * from hs_office_person as p where p.uuid = NEW.relHolderUuid INTO newHolderPerson; + assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.relHolderUuid = %s', NEW.relHolderUuid); + + select * from hs_office_person as p where p.uuid = OLD.relAnchorUuid INTO oldAnchorPerson; + assert oldAnchorPerson.uuid is not null, format('oldAnchorPerson must not be null for OLD.relAnchorUuid = %s', OLD.relAnchorUuid); + + select * from hs_office_person as p where p.uuid = NEW.relAnchorUuid INTO newAnchorPerson; + assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.relAnchorUuid = %s', NEW.relAnchorUuid); + + 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(hsOfficeRelationshipTenant(OLD), hsOfficeContactAdmin(oldContact)); + call grantRoleToRole(hsOfficeRelationshipTenant(NEW), hsOfficeContactAdmin(newContact)); + + call revokeRoleFromRole(hsOfficeContactReferrer(oldContact), hsOfficeRelationshipTenant(OLD)); + call grantRoleToRole(hsOfficeContactReferrer(newContact), hsOfficeRelationshipTenant(NEW)); + + end if; + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to re-wire the grant structure for a new hs_office_relationship row. + */ + +create or replace function updateTriggerForHsOfficeRelationship_tf() + returns trigger + language plpgsql + strict as $$ +begin + call updateRbacRulesForHsOfficeRelationship(OLD, NEW); + return NEW; +end; $$; + +create trigger updateTriggerForHsOfficeRelationship_tg + after update on hs_office_relationship + for each row +execute procedure updateTriggerForHsOfficeRelationship_tf(); --// +-- ============================================================================ +--changeset hs-office-relationship-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +-- FIXME: Where is this case necessary? +create trigger hs_office_relationship_insert_permission_check_tg + before insert on hs_office_relationship + for each row + -- As there is no explicit INSERT grant specified for this table, + -- only global admins are allowed to insert any rows. + when ( not isGlobalAdmin() ) + execute procedure hs_office_relationship_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-relationship-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +call generateRbacIdentityViewFromProjection('hs_office_relationship', $idName$ + (select idName from hs_office_person_iv p where p.uuid = relAnchorUuid) + || '-with-' || target.relType || '-' + || (select idName from hs_office_person_iv p where p.uuid = relHolderUuid) + + $idName$); +--// + -- ============================================================================ --changeset hs-office-relationship-rbac-RESTRICTED-VIEW:1 endDelimiter:--// -- ---------------------------------------------------------------------------- call generateRbacRestrictedView('hs_office_relationship', - '(select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)', - $updates$ - contactUuid = new.contactUuid + $orderBy$ + (select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid) + $orderBy$, + $updates$ + contactUuid = new.contactUuid $updates$); --// --- TODO: exception if one tries to amend any other column - - --- ============================================================================ ---changeset hs-office-relationship-rbac-NEW-RELATHIONSHIP:1 endDelimiter:--// --- ---------------------------------------------------------------------------- -/* - Creates a global permission for new-relationship and assigns it to the hostsharing admins role. - */ -do language plpgsql $$ - declare - addCustomerPermissions uuid[]; - globalObjectUuid uuid; - globalAdminRoleUuid uuid ; - begin - call defineContext('granting global new-relationship permission to global admin role', null, null, null); - - globalAdminRoleUuid := findRoleId(globalAdmin()); - globalObjectUuid := (select uuid from global); - addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-relationship']); - call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions); - end; -$$; - -/** - Used by the trigger to prevent the add-customer to current user respectively assumed roles. - */ -create or replace function addHsOfficeRelationshipNotAllowedForCurrentSubjects() - returns trigger - language PLPGSQL -as $$ -begin - raise exception '[403] new-relationship not permitted for %', - array_to_string(currentSubjects(), ';', 'null'); -end; $$; - -/** - Checks if the user or assumed roles are allowed to create a new customer. - */ -create trigger hs_office_relationship_insert_trigger - before insert - on hs_office_relationship - for each row - -- TODO.spec: who is allowed to create new relationships - when ( not hasAssumedRole() ) -execute procedure addHsOfficeRelationshipNotAllowedForCurrentSubjects(); ---// -