From 2774707801a52fd0010d8c7f2be5d0e97603e403 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Wed, 13 Mar 2024 17:02:49 +0100 Subject: [PATCH] WIP --- .../debitor/HsOfficeDebitorRepository.java | 17 +- .../partner/HsOfficePartnerDetailsEntity.java | 17 +- .../office/partner/HsOfficePartnerEntity.java | 14 +- .../office/person/HsOfficePersonEntity.java | 21 +- .../resources/db/changelog/050-rbac-base.sql | 1 + .../db/changelog/213-hs-office-person-rbac.md | 45 +++ .../changelog/213-hs-office-person-rbac.sql | 20 +- .../changelog/233-hs-office-partner-rbac.md | 6 +- .../changelog/233-hs-office-partner-rbac.sql | 354 +++++++----------- .../234-hs-office-partner-details-rbac.md | 23 ++ .../234-hs-office-partner-details-rbac.sql | 187 ++++++--- .../313-hs-office-coopshares-rbac.sql | 2 +- .../323-hs-office-coopassets-rbac.sql | 2 +- ...fficePartnerRepositoryIntegrationTest.java | 3 +- ...OfficePersonRepositoryIntegrationTest.java | 4 +- 15 files changed, 374 insertions(+), 342 deletions(-) create mode 100644 src/main/resources/db/changelog/213-hs-office-person-rbac.md create mode 100644 src/main/resources/db/changelog/234-hs-office-partner-details-rbac.md diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java index 2c0f865c..81a82625 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java @@ -13,7 +13,10 @@ public interface HsOfficeDebitorRepository extends Repository findDebitorByDebitorNumber(int partnerNumber, byte debitorNumberSuffix); @@ -24,11 +27,15 @@ public interface HsOfficeDebitorRepository extends Repository partnerRel.relAnchor? .importRootEntityAliasProxy("partnerRel", HsOfficeRelationshipEntity.class, @@ -122,6 +114,6 @@ public class HsOfficePartnerEntity implements Stringifyable, HasUuid { } public static void main(String[] args) throws IOException { - rbac().generateWithBaseFileName("233-hs-office-partner-rbac-generated"); + rbac().generateWithBaseFileName("233-hs-office-partner-rbac"); } } 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 7770608a..1a22c169 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 @@ -10,6 +10,7 @@ import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL; import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringifyable; import org.apache.commons.lang3.StringUtils; +import org.hibernate.annotations.JoinFormula; import jakarta.persistence.*; import java.io.IOException; @@ -55,15 +56,17 @@ public class HsOfficePersonEntity implements HasUuid, Stringifyable { @Column(name = "givenname") private String givenName; - @OneToOne(cascade = CascadeType.ALL) - @JoinTable(name = "hs_office_relationship", - joinColumns = - { @JoinColumn(name = "uuid", referencedColumnName = "relanchoruuid") }, - inverseJoinColumns = - { @JoinColumn(name = "relanchoruuid", referencedColumnName = "uuid") }) - private HsOfficePartnerEntity optionalPartner; - - @Override + @ManyToOne(cascade = CascadeType.ALL) + @JoinFormula( + referencedColumnName = "uuid", + value = """ + (SELECT partner.uuid AS uuid + FROM hs_office_partner partner + JOIN hs_office_relationship partnerRel + ON partnerRel.uuid = partner.partnerRoleUuid AND partnerRel.relType = 'PARTNER' + WHERE partnerRel.relHolderUuid = h1_0.uuid) + """) // FIXME: h1_0 is the generated self-reference, I should find a better solution + private HsOfficePartnerEntity optionalPartner; @Override public String toString() { return toString.apply(this); } diff --git a/src/main/resources/db/changelog/050-rbac-base.sql b/src/main/resources/db/changelog/050-rbac-base.sql index 26a8410a..c6d6ba13 100644 --- a/src/main/resources/db/changelog/050-rbac-base.sql +++ b/src/main/resources/db/changelog/050-rbac-base.sql @@ -698,6 +698,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); diff --git a/src/main/resources/db/changelog/213-hs-office-person-rbac.md b/src/main/resources/db/changelog/213-hs-office-person-rbac.md new file mode 100644 index 00000000..d62575d8 --- /dev/null +++ b/src/main/resources/db/changelog/213-hs-office-person-rbac.md @@ -0,0 +1,45 @@ +### rbac person + +This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-13T15:28:12.347550922. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph person["`**person**`"] + direction TB + style person fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph person:roles[ ] + style person:roles fill:#dd4901,stroke:white + + role:person:owner[[person:owner]] + role:person:admin[[person:admin]] + role:person:referrer[[person:referrer]] + end + + subgraph person:permissions[ ] + style person:permissions fill:#dd4901,stroke:white + + perm:person:INSERT{{person:INSERT}} + perm:person:DELETE{{person:DELETE}} + perm:person:UPDATE{{person:UPDATE}} + perm:person:SELECT{{person:SELECT}} + end +end + +%% granting roles to users +user:creator ==> role:person:owner + +%% granting roles to roles +role:global:admin ==> role:person:owner +role:person:owner ==> role:person:admin +role:person:admin ==> role:person:referrer + +%% granting permissions to roles +role:global:guest ==> perm:person:INSERT +role:person:owner ==> perm:person:DELETE +role:person:admin ==> perm:person:UPDATE +role:person:referrer ==> perm:person:SELECT + +``` diff --git a/src/main/resources/db/changelog/213-hs-office-person-rbac.sql b/src/main/resources/db/changelog/213-hs-office-person-rbac.sql index a15901da..3444c872 100644 --- a/src/main/resources/db/changelog/213-hs-office-person-rbac.sql +++ b/src/main/resources/db/changelog/213-hs-office-person-rbac.sql @@ -1,5 +1,6 @@ --liquibase formatted sql --- This code generated was by RbacViewPostgresGenerator at 2024-03-11T15:13:04.479330676. +-- This code generated was by RbacViewPostgresGenerator at 2024-03-13T15:28:12.357028926. + -- ============================================================================ --changeset hs-office-person-rbac-OBJECT:1 endDelimiter:--// @@ -72,9 +73,9 @@ create trigger insertTriggerForHsOfficePerson_tg after insert on hs_office_person for each row execute procedure insertTriggerForHsOfficePerson_tf(); - --// + -- ============================================================================ --changeset hs-office-person-rbac-INSERT:1 endDelimiter:--// -- ---------------------------------------------------------------------------- @@ -108,8 +109,8 @@ create or replace function hs_office_person_global_insert_tf() strict as $$ begin call grantPermissionToRole( - createPermission(NEW.uuid, 'INSERT', 'hs_office_person'), - globalGuest()); + globalGuest(), + createPermission(NEW.uuid, 'INSERT', 'hs_office_person')); return NEW; end; $$; @@ -128,8 +129,8 @@ begin raise exception '[403] insert into hs_office_person not allowed for current subjects % (%)', currentSubjects(), currentSubjectsUuids(); end; $$; - --// + -- ============================================================================ --changeset hs-office-person-rbac-IDENTITY-VIEW:1 endDelimiter:--// -- ---------------------------------------------------------------------------- @@ -137,19 +138,20 @@ end; $$; call generateRbacIdentityViewFromProjection('hs_office_person', $idName$ concat(tradeName, familyName, givenName) $idName$); - --// + -- ============================================================================ --changeset hs-office-person-rbac-RESTRICTED-VIEW:1 endDelimiter:--// -- ---------------------------------------------------------------------------- call generateRbacRestrictedView('hs_office_person', - 'concat(tradeName, familyName, givenName)', + $orderBy$ + concat(tradeName, familyName, givenName) + $orderBy$, $updates$ - personType = new.personType, + personType = new.personType, tradeName = new.tradeName, givenName = new.givenName, familyName = new.familyName $updates$); --// - diff --git a/src/main/resources/db/changelog/233-hs-office-partner-rbac.md b/src/main/resources/db/changelog/233-hs-office-partner-rbac.md index 8c321664..f7e11ae9 100644 --- a/src/main/resources/db/changelog/233-hs-office-partner-rbac.md +++ b/src/main/resources/db/changelog/233-hs-office-partner-rbac.md @@ -1,6 +1,6 @@ ### rbac partner -This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-11T15:29:41.494727519. +This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-13T15:28:17.873062752. ```mermaid %%{init:{'flowchart':{'htmlLabels':false}}}%% @@ -26,7 +26,7 @@ subgraph partner["`**partner**`"] subgraph partner:permissions[ ] style partner:permissions fill:#dd4901,stroke:white - perm:partner:new-partner{{partner:new-partner}} + perm:partner:INSERT{{partner:INSERT}} perm:partner:DELETE{{partner:DELETE}} perm:partner:UPDATE{{partner:UPDATE}} perm:partner:SELECT{{partner:SELECT}} @@ -147,7 +147,7 @@ role:partnerRel:tenant -.-> role:partnerRel.holderPerson:referrer role:partnerRel:tenant -.-> role:partnerRel.contact:referrer %% granting permissions to roles -role:global:admin ==> perm:partner:new-partner +role:global:admin ==> perm:partner:INSERT role:partnerRel:admin ==> perm:partner:DELETE role:partnerRel:agent ==> perm:partner:UPDATE role:partnerRel:tenant ==> perm:partner:SELECT diff --git a/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql b/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql index c91e15b1..b086f92d 100644 --- a/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql +++ b/src/main/resources/db/changelog/233-hs-office-partner-rbac.sql @@ -1,4 +1,6 @@ --liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator at 2024-03-13T15:28:17.881206014. + -- ============================================================================ --changeset hs-office-partner-rbac-OBJECT:1 endDelimiter:--// @@ -8,245 +10,147 @@ call generateRelatedRbacObject('hs_office_partner'); -- ============================================================================ ---changeset hs-office-partner-rbac-ROLES-CREATION:1 endDelimiter:--// +--changeset hs-office-partner-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// -- ---------------------------------------------------------------------------- - -/* - Creates and updates the roles and their assignments for partner entities. - */ - -create or replace function hsOfficePartnerRbacRolesTrigger() - returns trigger - language plpgsql - strict as $$ -declare - partnerUuid uuid default new.uuid; - partnerDetailsUuid uuid default new.detailsUuid; - oldPartnerRel hs_office_relationship; - newPartnerRel hs_office_relationship; - -begin - call enterTriggerForObjectUuid(NEW.uuid); - - select * from hs_office_relationship as r where r.uuid = NEW.partnerroleuuid into newPartnerRel; - - if TG_OP = 'INSERT' then - - -- Permissions and Grants for Partner - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipOwner(newPartnerRel)), - createPermissions(partnerUuid, array ['DELETE']) - ); - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipAdmin(newPartnerRel)), - createPermissions(partnerUuid, array ['UPDATE']) - ); - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipTenant(newPartnerRel)), - createPermissions(partnerUuid, array ['SELECT']) - ); - - -- Permissions and Grants for PartnerDetails - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipOwner(newPartnerRel)), - createPermissions(partnerDetailsUuid, array ['DELETE']) - ); - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipAdmin(newPartnerRel)), - createPermissions(partnerDetailsUuid, array ['UPDATE']) - ); - - call grantPermissionsToRole( - -- Yes, here hsOfficePartnerAGENT is used, not hsOfficeRelationshipTENANT. - -- Do NOT grant view permission on partner-details to hsOfficeRelationshipTENANT! - -- Otherwise package-admins etc. would be able to read the data. - getRoleId(hsOfficeRelationshipAgent(newPartnerRel)), - createPermissions(partnerDetailsUuid, array ['SELECT']) - ); - - - elsif TG_OP = 'UPDATE' then - - if OLD.partnerRoleUuid <> NEW.partnerRoleUuid then - select * from hs_office_relationship as r where r.uuid = OLD.partnerRoleUuid into oldPartnerRel; - - -- Revokes from Partner - - call revokePermissionFromRole( - findPermissionId(partnerUuid, 'SELECT'), - hsOfficeRelationshipTenant(oldPartnerRel) - ); - - -- call revokePermissionFromRole( - -- findPermissionId(partnerUuid, 'edit'), - -- hsOfficeRelationshipAdmin(oldPartnerRel) - -- ); - -- - -- call revokePermissionFromRole( - -- findPermissionId(partnerUuid, '*'), - -- hsOfficeRelationshipOwner(oldPartnerRel) - -- ); - - -- Grants for Partner - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipOwner(newPartnerRel)), - array[findPermissionId(partnerUuid, 'DELETE')] - ); - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipAdmin(newPartnerRel)), - array[findPermissionId(partnerUuid, 'UPDATE')] - ); - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipTenant(newPartnerRel)), - array[findPermissionId(partnerUuid, 'SELECT')] - ); - - -- Revokes from PartnerDetails - - -- call revokePermissionFromRole( - -- findPermissionId(partnerDetailsUuid, 'SELECT'), - -- hsOfficeRelationshipAgent(oldPartnerRel) - -- ); - -- - -- call revokePermissionFromRole( - -- findPermissionId(partnerDetailsUuid, 'UPDATE'), - -- hsOfficeRelationshipAdmin(oldPartnerRel) - -- ); - -- - -- call revokePermissionFromRole( - -- findPermissionId(partnerDetailsUuid, 'DELETE'), - -- hsOfficeRelationshipOwner(oldPartnerRel) - -- ); - - -- Grants for PartnerDetails - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipOwner(newPartnerRel)), - array[findPermissionId(partnerDetailsUuid, 'DELETE')] - ); - - call grantPermissionsToRole( - getRoleId(hsOfficeRelationshipAdmin(newPartnerRel)), - array[findPermissionId(partnerDetailsUuid, 'UPDATE')] - ); - - call grantPermissionsToRole( - -- Yes, here hsOfficePartnerAGENT is used, not hsOfficePartnerTENANT. - -- Do NOT grant view permission on partner-details to hsOfficeRelationshipTENANT! - -- Otherwise package-admins etc. would be able to read the data. - getRoleId(hsOfficeRelationshipAgent(newPartnerRel)), - array[findPermissionId(partnerDetailsUuid, 'SELECT')] - ); - - end if; - - else - raise exception 'invalid usage of TRIGGER'; - end if; - - call leaveTriggerForObjectUuid(partnerUuid); - return NEW; -end; $$; - -/* - An AFTER INSERT TRIGGER which creates the role structure for a new customer. - */ -create trigger createRbacRolesForHsOfficePartner_Trigger - after insert - on hs_office_partner - for each row -execute procedure hsOfficePartnerRbacRolesTrigger(); - -/* - An AFTER UPDATE TRIGGER which updates the role structure of a customer. - */ -create trigger updateRbacRolesForHsOfficePartner_Trigger - after update - on hs_office_partner - for each row -execute procedure hsOfficePartnerRbacRolesTrigger(); +call generateRbacRoleDescriptors('hsOfficePartner', 'hs_office_partner'); --// -- ============================================================================ ---changeset hs-office-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--// +--changeset hs-office-partner-rbac-insert-trigger:1 endDelimiter:--// -- ---------------------------------------------------------------------------- -call generateRbacIdentityViewFromProjection('hs_office_partner', $idName$ - partnerNumber || ':' || - (select idName - from hs_office_person_iv p - left join hs_office_relationship r on r.uuid = target.partnerRoleUuid - where p.uuid = r.relHolderUuid) - || '-' || - (select idName - from hs_office_contact_iv c - left join hs_office_relationship r on r.uuid = target.partnerRoleUuid - where c.uuid = r.contactUuid) - $idName$); + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficePartner( + NEW hs_office_partner +) + language plpgsql as $$ + +declare + newPartnerRel hs_office_relationship; + newPartnerDetails hs_office_partner_details; + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + SELECT * FROM hs_office_relationship AS r WHERE r.uuid = NEW.partnerRoleUuid INTO newPartnerRel; + assert newPartnerRel.uuid is not null, format('newPartnerRel must not be null for NEW.partnerRelUuid = %s', NEW.partnerRelUuid); + + SELECT * FROM hs_office_partner_details AS d WHERE d.uuid = NEW.detailsUuid INTO newPartnerDetails; + assert newPartnerDetails.uuid is not null, format('newPartnerDetails must not be null for NEW.detailsUuid = %s', NEW.detailsUuid); + + call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), hsOfficeRelationshipAdmin(newPartnerRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationshipTenant(newPartnerRel)); + call grantPermissionToRole(createPermission(NEW.uuid, 'UPDATE'), hsOfficeRelationshipAgent(newPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'DELETE'), hsOfficeRelationshipAdmin(newPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'SELECT'), hsOfficeRelationshipAgent(newPartnerRel)); + call grantPermissionToRole(createPermission(newPartnerDetails.uuid, 'UPDATE'), hsOfficeRelationshipAgent(newPartnerRel)); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_partner row. + */ + +create or replace function insertTriggerForHsOfficePartner_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficePartner(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficePartner_tg + after insert on hs_office_partner + for each row +execute procedure insertTriggerForHsOfficePartner_tf(); --// +-- ============================================================================ +--changeset hs-office-partner-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates INSERT INTO hs_office_partner permissions for the related global rows. + */ +do language plpgsql $$ + declare + row global; + permissionUuid uuid; + roleUuid uuid; + begin + call defineContext('create INSERT INTO hs_office_partner permissions for the related global rows'); + + FOR row IN SELECT * FROM global + LOOP + roleUuid := findRoleId(globalAdmin()); + permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_partner'); + call grantPermissionToRole(permissionUuid, roleUuid); + END LOOP; + END; +$$; + +/** + Adds hs_office_partner INSERT permission to specified role of new global rows. +*/ +create or replace function hs_office_partner_global_insert_tf() + returns trigger + language plpgsql + strict as $$ +begin + call grantPermissionToRole( + globalAdmin(), + createPermission(NEW.uuid, 'INSERT', 'hs_office_partner')); + return NEW; +end; $$; + +create trigger hs_office_partner_global_insert_tg + after insert on global + for each row +execute procedure hs_office_partner_global_insert_tf(); + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_partner. +*/ +create or replace function hs_office_partner_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_partner not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_partner_insert_permission_check_tg + before insert on hs_office_partner + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_partner_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +call generateRbacIdentityViewFromProjection('hs_office_partner', $idName$ + 'P-' || partnerNumber + $idName$); +--// + -- ============================================================================ --changeset hs-office-partner-rbac-RESTRICTED-VIEW:1 endDelimiter:--// -- ---------------------------------------------------------------------------- call generateRbacRestrictedView('hs_office_partner', - 'target.partnerNumber', + $orderBy$ + 'P-' || partnerNumber + $orderBy$, $updates$ - partnerRoleUuid = new.partnerRoleUuid + partnerroleuuid = new.partnerroleuuid $updates$); --// - --- ============================================================================ ---changeset hs-office-partner-rbac-NEW-PARTNER:1 endDelimiter:--// --- ---------------------------------------------------------------------------- -/* - Creates a global permission for new-partner and assigns it to the Hostsharing admins role. - */ -do language plpgsql $$ - declare - addCustomerPermissions uuid[]; - globalObjectUuid uuid; - globalAdminRoleUuid uuid ; - begin - call defineContext('granting global new-partner permission to global admin role', null, null, null); - - globalAdminRoleUuid := findRoleId(globalAdmin()); - globalObjectUuid := (select uuid from global); - addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-partner']); - call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions); - end; -$$; - -/** - Used by the trigger to prevent the add-customer to current user respectively assumed roles. - */ -create or replace function addHsOfficePartnerNotAllowedForCurrentSubjects() - returns trigger - language PLPGSQL -as $$ -begin - raise exception '[403] new-partner 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_partner_insert_trigger - before insert - on hs_office_partner - for each row - -- TODO.spec: who is allowed to create new partners - when ( not hasAssumedRole() ) -execute procedure addHsOfficePartnerNotAllowedForCurrentSubjects(); ---// - diff --git a/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.md b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.md new file mode 100644 index 00000000..4f699ab4 --- /dev/null +++ b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.md @@ -0,0 +1,23 @@ +### rbac partnerDetails + +This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-13T15:35:19.438833295. + +```mermaid +%%{init:{'flowchart':{'htmlLabels':false}}}%% +flowchart TB + +subgraph partnerDetails["`**partnerDetails**`"] + direction TB + style partnerDetails fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph partnerDetails:permissions[ ] + style partnerDetails:permissions fill:#dd4901,stroke:white + + perm:partnerDetails:INSERT{{partnerDetails:INSERT}} + end +end + +%% granting permissions to roles +role:global:admin ==> perm:partnerDetails:INSERT + +``` diff --git a/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.sql b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.sql index 60986852..26aa4169 100644 --- a/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.sql +++ b/src/main/resources/db/changelog/234-hs-office-partner-details-rbac.sql @@ -1,4 +1,6 @@ --liquibase formatted sql +-- This code generated was by RbacViewPostgresGenerator at 2024-03-13T15:35:19.446996853. + -- ============================================================================ --changeset hs-office-partner-details-rbac-OBJECT:1 endDelimiter:--// @@ -8,76 +10,141 @@ call generateRelatedRbacObject('hs_office_partner_details'); -- ============================================================================ ---changeset hs-office-partner-details-rbac-IDENTITY-VIEW:1 endDelimiter:--// +--changeset hs-office-partner-details-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// -- ---------------------------------------------------------------------------- -call generateRbacIdentityViewFromProjection('hs_office_partner_details', $idName$ - (select idName || '-details' from hs_office_partner_iv partner_iv - join hs_office_partner partner on (partner_iv.uuid = partner.uuid) - where partner.detailsUuid = target.uuid) - $idName$); +call generateRbacRoleDescriptors('hsOfficePartnerDetails', 'hs_office_partner_details'); --// +-- ============================================================================ +--changeset hs-office-partner-details-rbac-insert-trigger:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates the roles, grants and permission for the AFTER INSERT TRIGGER. + */ + +create or replace procedure buildRbacSystemForHsOfficePartnerDetails( + NEW hs_office_partner_details +) + language plpgsql as $$ + +declare + +begin + call enterTriggerForObjectUuid(NEW.uuid); + + call leaveTriggerForObjectUuid(NEW.uuid); +end; $$; + +/* + AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_partner_details row. + */ + +create or replace function insertTriggerForHsOfficePartnerDetails_tf() + returns trigger + language plpgsql + strict as $$ +begin + call buildRbacSystemForHsOfficePartnerDetails(NEW); + return NEW; +end; $$; + +create trigger insertTriggerForHsOfficePartnerDetails_tg + after insert on hs_office_partner_details + for each row +execute procedure insertTriggerForHsOfficePartnerDetails_tf(); +--// + + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-INSERT:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + +/* + Creates INSERT INTO hs_office_partner_details permissions for the related global rows. + */ +do language plpgsql $$ + declare + row global; + permissionUuid uuid; + roleUuid uuid; + begin + call defineContext('create INSERT INTO hs_office_partner_details permissions for the related global rows'); + + FOR row IN SELECT * FROM global + LOOP + roleUuid := findRoleId(globalAdmin()); + permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_partner_details'); + call grantPermissionToRole(permissionUuid, roleUuid); + END LOOP; + END; +$$; + +/** + Adds hs_office_partner_details INSERT permission to specified role of new global rows. +*/ +create or replace function hs_office_partner_details_global_insert_tf() + returns trigger + language plpgsql + strict as $$ +begin + call grantPermissionToRole( + globalAdmin(), + createPermission(NEW.uuid, 'INSERT', 'hs_office_partner_details')); + return NEW; +end; $$; + +create trigger hs_office_partner_details_global_insert_tg + after insert on global + for each row +execute procedure hs_office_partner_details_global_insert_tf(); + +/** + Checks if the user or assumed roles are allowed to insert a row to hs_office_partner_details. +*/ +create or replace function hs_office_partner_details_insert_permission_missing_tf() + returns trigger + language plpgsql as $$ +begin + raise exception '[403] insert into hs_office_partner_details not allowed for current subjects % (%)', + currentSubjects(), currentSubjectsUuids(); +end; $$; + +create trigger hs_office_partner_details_insert_permission_check_tg + before insert on hs_office_partner_details + for each row + when ( not isGlobalAdmin() ) + execute procedure hs_office_partner_details_insert_permission_missing_tf(); +--// + +-- ============================================================================ +--changeset hs-office-partner-details-rbac-IDENTITY-VIEW:1 endDelimiter:--// +-- ---------------------------------------------------------------------------- + + call generateRbacIdentityViewFromQuery('hs_office_partner_details', $idName$ + SELECT partnerDetails.uuid as uuid, partner_iv.idName || '-details' as idName + FROM hs_office_partner_details AS partnerDetails + JOIN hs_office_partner partner ON partner.detailsUuid = partnerDetails.uuid + JOIN hs_office_partner_iv partner_iv ON partner_iv.uuid = partner.uuid + + $idName$); +--// + -- ============================================================================ --changeset hs-office-partner-details-rbac-RESTRICTED-VIEW:1 endDelimiter:--// -- ---------------------------------------------------------------------------- call generateRbacRestrictedView('hs_office_partner_details', - 'target.uuid', -- no specific order required + $orderBy$ + uuid + $orderBy$, $updates$ - registrationOffice = new.registrationOffice, + registrationOffice = new.registrationOffice, registrationNumber = new.registrationNumber, - birthPlace = new.birthPlace, - birthName = new.birthName, - birthday = new.birthday, - dateOfDeath = new.dateOfDeath + birthPlace = new.birthPlace, + birthName = new.birthName, + birthday = new.birthday, + dateOfDeath = new.dateOfDeath $updates$); --// - --- ============================================================================ ---changeset hs-office-partner-details-rbac-NEW-PARTNER-DETAILS:1 endDelimiter:--// --- ---------------------------------------------------------------------------- -/* - Creates a global permission for new-partner-details and assigns it to the hostsharing admins role. - */ -do language plpgsql $$ - declare - addCustomerPermissions uuid[]; - globalObjectUuid uuid; - globalAdminRoleUuid uuid ; - begin - call defineContext('granting global new-partner-details permission to global admin role', null, null, null); - - globalAdminRoleUuid := findRoleId(globalAdmin()); - globalObjectUuid := (select uuid from global); - addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-partner-details']); - call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions); - end; -$$; - --- TODO.refa: the code below could be moved to a generator, maybe even the code above. --- Additionally, the code below is not necessary for all entities, specify when it is! - -/** - Used by the trigger to prevent the add-partner-details to current user respectively assumed roles. - */ -create or replace function addHsOfficePartnerDetailsNotAllowedForCurrentSubjects() - returns trigger - language PLPGSQL -as $$ -begin - raise exception '[403] new-partner-details not permitted for %', - array_to_string(currentSubjects(), ';', 'null'); -end; $$; - -/** - Checks if the user or assumed roles are allowed to create new partner-details. - */ -create trigger hs_office_partner_details_insert_trigger - before insert - on hs_office_partner_details - for each row - when ( not hasAssumedRole() ) -execute procedure addHsOfficePartnerDetailsNotAllowedForCurrentSubjects(); ---// - diff --git a/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql b/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql index 5ee8bfbe..a4cac136 100644 --- a/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql +++ b/src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql @@ -42,7 +42,7 @@ begin -- coopsharestransactions cannot be edited nor deleted, just created+viewed call grantPermissionsToRole( - getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership)), + getRoleId(hsOfficeMembershipReferrer(newHsOfficeMembership)), createPermissions(NEW.uuid, array ['SELECT']) ); diff --git a/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql b/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql index 69920385..035da07b 100644 --- a/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql +++ b/src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql @@ -42,7 +42,7 @@ begin -- coopassetstransactions cannot be edited nor deleted, just created+viewed call grantPermissionsToRole( - getRoleId(hsOfficeMembershipTenant(newHsOfficeMembership)), + getRoleId(hsOfficeMembershipReferrer(newHsOfficeMembership)), createPermissions(NEW.uuid, array ['SELECT']) ); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java index 6bfd513e..e06e0ed6 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java @@ -286,7 +286,6 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean "hs_office_person#ErbenBesslerMelBessler.admin"); assertThatPartnerActuallyInDatabase(givenPartner); - // when final var result = jpaAttempt.transacted(() -> { context("superuser-alex@hostsharing.net"); @@ -332,7 +331,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean private void assertThatPartnerActuallyInDatabase(final HsOfficePartnerEntity saved) { final var found = partnerRepo.findByUuid(saved.getUuid()); - assertThat(found).isNotEmpty().get().isNotSameAs(saved).usingRecursiveComparison().isEqualTo(saved); + assertThat(found).isNotEmpty().get().isNotSameAs(saved).extracting(HsOfficePartnerEntity::toString).isEqualTo(saved.toString()); } private void assertThatPartnerIsVisibleForUserWithRole( diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java index f92fea7b..0facd7d0 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java @@ -110,11 +110,9 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTestWithCleanu assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder( Array.from( initialGrantNames, - "{ grant perm * on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.owner by system and assume }", - "{ grant role hs_office_person#anothernewperson.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }", + "{ grant role hs_office_person#anothernewperson.owner to user selfregistered-user-drew@hostsharing.org by hs_office_person#anothernewperson.owner and assume }", "{ grant role hs_office_person#anothernewperson.owner to role global#global.admin by system and assume }", "{ grant perm UPDATE on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.admin by system and assume }", - "{ grant role hs_office_person#anothernewperson.tenant to role hs_office_person#anothernewperson.admin by system and assume }", "{ grant perm DELETE on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.owner by system and assume }", "{ grant role hs_office_person#anothernewperson.admin to role hs_office_person#anothernewperson.owner by system and assume }",