From cb8a5190cef6f6adff65c44e042e7505572b5189 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 10 Oct 2024 09:31:43 +0200 Subject: [PATCH] fix allowed licenses, do version upgrades upgrade and improve test coverage (#112) Co-authored-by: Michael Hoennig Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/112 Reviewed-by: Marc Sandlus --- README.md | 12 +- build.gradle | 37 ++-- etc/allowed-licenses.json | 19 +- etc/owasp-dependency-check-suppression.xml | 13 +- .../hsadminng/hs/migration/CsvDataImport.java | 14 +- .../hs/migration/ImportHostingAssets.java | 18 +- .../HsOfficeBankAccountEntityUnitTest.java | 45 ++++ .../contact/HsOfficeContactUnitTest.java | 45 ++++ ...ceCoopAssetsTransactionEntityUnitTest.java | 120 +++++++++++ ...ceCoopSharesTransactionEntityUnitTest.java | 120 +++++++++++ .../HsOfficeDebitorEntityUnitTest.java | 198 ++++++++++++++++++ .../HsOfficeMembershipEntityUnitTest.java | 121 +++++++++++ .../HsOfficePartnerEntityUnitTest.java | 120 +++++++++++ .../person/HsOfficePersonEntityUnitTest.java | 47 +++++ .../relation/HsOfficeRelationUnitTest.java | 100 +++++++++ .../HsOfficeSepaMandateEntityUnitTest.java | 141 +++++++++++++ 16 files changed, 1125 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index e1d1515b..308d5c51 100644 --- a/README.md +++ b/README.md @@ -497,9 +497,19 @@ We'll see if this changes when the project progresses and more validations are a ### OWASP Security Vulnerability Check -An OWASP security vulnerability is configured and can be utilized by running: +An OWASP security vulnerability is configured, but you need an API key. +Fetch it from https://nvd.nist.gov/developers/request-an-api-key. + +Then add it to your `~/.gradle/gradle.properties` file: + +``` +OWASP_API_KEY=........-....-....-....-............ +``` + +Now you can run the dependency vulnerability check: ```shell +gw dependencyCheckUpdate gw dependencyCheckAnalyze ``` diff --git a/build.gradle b/build.gradle index 41ceaed8..80e74606 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,10 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.2.4' - id 'io.spring.dependency-management' version '1.1.4' + id 'org.springframework.boot' version '3.3.4' + id 'io.spring.dependency-management' version '1.1.6' id 'io.openapiprocessor.openapi-processor' version '2023.2' - id 'com.github.jk1.dependency-license-report' version '2.6' - id "org.owasp.dependencycheck" version "9.0.10" + id 'com.github.jk1.dependency-license-report' version '2.9' + id "org.owasp.dependencycheck" version "10.0.4" id "com.diffplug.spotless" version "6.25.0" id 'jacoco' id 'info.solidsoft.pitest' version '1.15.0' @@ -58,19 +58,20 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-jdbc' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.9.1' - implementation 'org.springdoc:springdoc-openapi:2.4.0' - implementation 'org.postgresql:postgresql:42.7.3' - implementation 'org.liquibase:liquibase-core:4.27.0' - implementation 'io.hypersistence:hypersistence-utils-hibernate-63:3.7.3' - implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.0' + implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.9.2' + implementation 'org.springdoc:springdoc-openapi:2.6.0' + implementation 'org.postgresql:postgresql:42.7.4' + implementation 'org.liquibase:liquibase-core:4.29.2' + implementation 'io.hypersistence:hypersistence-utils-hibernate-63:3.8.3' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.0' implementation 'org.openapitools:jackson-databind-nullable:0.2.6' - implementation 'org.apache.commons:commons-text:1.11.0' - implementation 'net.java.dev.jna:jna:5.8.0' - implementation 'org.modelmapper:modelmapper:3.2.0' - implementation 'org.iban4j:iban4j:3.2.7-RELEASE' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.4.0' - implementation 'org.reflections:reflections:0.9.12' + implementation 'org.apache.commons:commons-text:1.12.0' + implementation 'net.java.dev.jna:jna:5.15.0' + implementation 'org.modelmapper:modelmapper:3.2.1' + implementation 'org.iban4j:iban4j:3.2.10-RELEASE' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0' + implementation 'org.webjars:swagger-ui:5.17.14' + implementation 'org.reflections:reflections:0.10.2' compileOnly 'org.projectlombok:lombok' testCompileOnly 'org.projectlombok:lombok' @@ -85,9 +86,9 @@ dependencies { testImplementation 'org.testcontainers:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.testcontainers:postgresql' - testImplementation 'com.tngtech.archunit:archunit-junit5:1.2.1' + testImplementation 'com.tngtech.archunit:archunit-junit5:1.3.0' testImplementation 'io.rest-assured:spring-mock-mvc' - testImplementation 'org.hamcrest:hamcrest-core:2.2' + testImplementation 'org.hamcrest:hamcrest-core:3.0' testImplementation 'org.pitest:pitest-junit5-plugin:1.2.1' testImplementation 'org.junit.jupiter:junit-jupiter-api' } diff --git a/etc/allowed-licenses.json b/etc/allowed-licenses.json index f50ce4b9..65aa236e 100644 --- a/etc/allowed-licenses.json +++ b/etc/allowed-licenses.json @@ -1,8 +1,10 @@ { "allowedLicenses": [ - { "moduleLicense": "Apache 2.0" }, { "moduleLicense": "Apache 2" }, + { "moduleLicense": "Apache 2.0" }, + { "moduleLicense": "Apache-2.0" }, { "moduleLicense": "Apache License 2.0" }, + { "moduleLicense": "Apache License v2.0" }, { "moduleLicense": "Apache License, Version 2.0" }, { "moduleLicense": "The Apache Software License, Version 2.0" }, @@ -11,6 +13,8 @@ { "moduleLicense": "BSD-3-Clause" }, { "moduleLicense": "The BSD License" }, + { "moduleLicense": "The New BSD License" }, + { "moduleLicense": "CDDL 1.1" }, { "moduleLicense": "CDDL/GPLv2+CE" }, { "moduleLicense": "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0" }, @@ -29,11 +33,22 @@ { "moduleLicense": "GNU General Public License, version 2 with the GNU Classpath Exception" }, { "moduleLicense": "GPL2 w/ CPE" }, + { "moduleLicense": "LGPL, version 2.1"}, + { "moduleLicense": "LGPL-2.1-or-later"}, + { "moduleLicense": "MIT License" }, { "moduleLicense": "MIT" }, { "moduleLicense": "The MIT License (MIT)" }, { "moduleLicense": "The MIT License" }, - { "moduleName": "org.springdoc:springdoc-openapi" } + { "moduleLicense": "WTFPL" }, + + { + "moduleLicense": null, + "#moduleLicense": "Apache License 2.0, see https://github.com/springdoc/springdoc-openapi/blob/main/LICENSE", + "moduleVersion": "2.4.0", + "moduleName": "org.springdoc:springdoc-openapi" + } + ] } diff --git a/etc/owasp-dependency-check-suppression.xml b/etc/owasp-dependency-check-suppression.xml index af4269d4..b407e289 100644 --- a/etc/owasp-dependency-check-suppression.xml +++ b/etc/owasp-dependency-check-suppression.xml @@ -1,12 +1,5 @@ - - - ^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$ - cpe:/a:fasterxml:jackson-databind - ^pkg:maven/org\.pitest/pitest\-command\-line@.*$ cpe:/a:line:line + + + CVE-2024-9329 + diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/CsvDataImport.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/CsvDataImport.java index b5b7de8e..d04fc0a5 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/CsvDataImport.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/CsvDataImport.java @@ -15,6 +15,7 @@ import org.opentest4j.AssertionFailedError; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.core.io.Resource; import org.springframework.transaction.support.TransactionTemplate; import jakarta.persistence.EntityManager; @@ -24,7 +25,6 @@ import jakarta.validation.ValidationException; import jakarta.validation.constraints.NotNull; import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; @@ -33,6 +33,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.time.LocalDate; import java.util.LinkedHashSet; import java.util.List; @@ -123,13 +124,10 @@ public class CsvDataImport extends ContextBasedTest { } } - protected String resourceAsString(@NotNull final String resourcePath) { - try (InputStream inputStream = requireNonNull(getClass().getClassLoader().getResourceAsStream(resourcePath)); - final var reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { - return reader.lines().collect(Collectors.joining(System.lineSeparator())); - } catch (Exception exc) { - throw new AssertionFailedError("cannot open '" + resourcePath + "'"); - } + @SneakyThrows + protected String resourceAsString(final Resource resource) { + final var lines = Files.readAllLines(resource.getFile().toPath(), StandardCharsets.UTF_8); + return String.join("\n", lines); } protected List withoutHeader(final List records) { diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java index 904149b4..a831f637 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java @@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.migration; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.hash.HashGenerator; import net.hostsharing.hsadminng.hash.HashGenerator.Algorithm; @@ -26,10 +27,9 @@ import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; -import org.reflections.Reflections; -import org.reflections.scanners.ResourcesScanner; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.test.annotation.Commit; import org.springframework.test.annotation.DirtiesContext; @@ -46,7 +46,6 @@ import java.util.TreeMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; -import java.util.regex.Pattern; import static java.util.Arrays.stream; import static java.util.Map.entry; @@ -497,13 +496,14 @@ public class ImportHostingAssets extends BaseOfficeDataImport { @Test @Order(16020) + @SneakyThrows void importZonenfiles() { - final var reflections = new Reflections(MIGRATION_DATA_PATH + "/hosting/zonefiles", new ResourcesScanner()); - final var zonefileFiles = reflections.getResources(Pattern.compile(".*\\.json")).stream().sorted().toList(); - zonefileFiles.forEach(zonenfileName -> { - System.out.println("Processing zonenfile: " + zonenfileName); - importZonefiles(vmName(zonenfileName), resourceAsString(zonenfileName)); - }); + final var resolver = new PathMatchingResourcePatternResolver(); + final var resources = resolver.getResources("/" + MIGRATION_DATA_PATH + "/hosting/zonefiles/*.json"); + for (var resource : resources) { + System.out.println("Processing zonenfile: " + resource); + importZonefiles(vmName(resource.getFilename()), resourceAsString(resource)); + } } @Test diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountEntityUnitTest.java index acd6c8f3..6367c56e 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountEntityUnitTest.java @@ -1,5 +1,6 @@ package net.hostsharing.hsadminng.hs.office.bankaccount; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -32,4 +33,48 @@ class HsOfficeBankAccountEntityUnitTest { assertThat(givenBankAccount.toShortString()).isEqualTo("given holder"); } + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficeBankAccountEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph bankAccount["`**bankAccount**`"] + direction TB + style bankAccount fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph bankAccount:roles[ ] + style bankAccount:roles fill:#dd4901,stroke:white + + role:bankAccount:OWNER[[bankAccount:OWNER]] + role:bankAccount:ADMIN[[bankAccount:ADMIN]] + role:bankAccount:REFERRER[[bankAccount:REFERRER]] + end + + subgraph bankAccount:permissions[ ] + style bankAccount:permissions fill:#dd4901,stroke:white + + perm:bankAccount:INSERT{{bankAccount:INSERT}} + perm:bankAccount:DELETE{{bankAccount:DELETE}} + perm:bankAccount:UPDATE{{bankAccount:UPDATE}} + perm:bankAccount:SELECT{{bankAccount:SELECT}} + end + end + + %% granting roles to users + user:creator ==> role:bankAccount:OWNER + + %% granting roles to roles + role:rbac.global:ADMIN ==> role:bankAccount:OWNER + role:bankAccount:OWNER ==> role:bankAccount:ADMIN + role:bankAccount:ADMIN ==> role:bankAccount:REFERRER + + %% granting permissions to roles + role:rbac.global:GUEST ==> perm:bankAccount:INSERT + role:bankAccount:OWNER ==> perm:bankAccount:DELETE + role:bankAccount:ADMIN ==> perm:bankAccount:UPDATE + role:bankAccount:REFERRER ==> perm:bankAccount:SELECT + """); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactUnitTest.java index 94f8e0b8..de61688a 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactUnitTest.java @@ -1,5 +1,6 @@ package net.hostsharing.hsadminng.hs.office.contact; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -18,4 +19,48 @@ class HsOfficeContactUnitTest { assertThat("" + givenContact).isEqualTo("contact(caption='given caption')"); } + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficeContactRbacEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph contact["`**contact**`"] + direction TB + style contact fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph contact:roles[ ] + style contact:roles fill:#dd4901,stroke:white + + role:contact:OWNER[[contact:OWNER]] + role:contact:ADMIN[[contact:ADMIN]] + role:contact:REFERRER[[contact:REFERRER]] + end + + subgraph contact:permissions[ ] + style contact:permissions fill:#dd4901,stroke:white + + perm:contact:DELETE{{contact:DELETE}} + perm:contact:UPDATE{{contact:UPDATE}} + perm:contact:SELECT{{contact:SELECT}} + perm:contact:INSERT{{contact:INSERT}} + end + end + + %% granting roles to users + user:creator ==> role:contact:OWNER + + %% granting roles to roles + role:rbac.global:ADMIN ==> role:contact:OWNER + role:contact:OWNER ==> role:contact:ADMIN + role:contact:ADMIN ==> role:contact:REFERRER + + %% granting permissions to roles + role:contact:OWNER ==> perm:contact:DELETE + role:contact:ADMIN ==> perm:contact:UPDATE + role:contact:REFERRER ==> perm:contact:SELECT + role:rbac.global:GUEST ==> perm:contact:INSERT + """); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntityUnitTest.java index aada2552..09f704d6 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntityUnitTest.java @@ -1,5 +1,6 @@ package net.hostsharing.hsadminng.hs.office.coopassets; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import java.math.BigDecimal; @@ -68,4 +69,123 @@ class HsOfficeCoopAssetsTransactionEntityUnitTest { assertThat(result).isEqualTo("M-???????:nul:+0.00"); } + + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficeCoopAssetsTransactionEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph coopAssetsTransaction["`**coopAssetsTransaction**`"] + direction TB + style coopAssetsTransaction fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph coopAssetsTransaction:permissions[ ] + style coopAssetsTransaction:permissions fill:#dd4901,stroke:white + + perm:coopAssetsTransaction:INSERT{{coopAssetsTransaction:INSERT}} + perm:coopAssetsTransaction:UPDATE{{coopAssetsTransaction:UPDATE}} + perm:coopAssetsTransaction:SELECT{{coopAssetsTransaction:SELECT}} + end + end + + subgraph membership["`**membership**`"] + direction TB + style membership fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership:roles[ ] + style membership:roles fill:#99bcdb,stroke:white + + role:membership:OWNER[[membership:OWNER]] + role:membership:ADMIN[[membership:ADMIN]] + role:membership:AGENT[[membership:AGENT]] + end + end + + subgraph membership.partnerRel["`**membership.partnerRel**`"] + direction TB + style membership.partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership.partnerRel:roles[ ] + style membership.partnerRel:roles fill:#99bcdb,stroke:white + + role:membership.partnerRel:OWNER[[membership.partnerRel:OWNER]] + role:membership.partnerRel:ADMIN[[membership.partnerRel:ADMIN]] + role:membership.partnerRel:AGENT[[membership.partnerRel:AGENT]] + role:membership.partnerRel:TENANT[[membership.partnerRel:TENANT]] + end + end + + subgraph membership.partnerRel.anchorPerson["`**membership.partnerRel.anchorPerson**`"] + direction TB + style membership.partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership.partnerRel.anchorPerson:roles[ ] + style membership.partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:membership.partnerRel.anchorPerson:OWNER[[membership.partnerRel.anchorPerson:OWNER]] + role:membership.partnerRel.anchorPerson:ADMIN[[membership.partnerRel.anchorPerson:ADMIN]] + role:membership.partnerRel.anchorPerson:REFERRER[[membership.partnerRel.anchorPerson:REFERRER]] + end + end + + subgraph membership.partnerRel.contact["`**membership.partnerRel.contact**`"] + direction TB + style membership.partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership.partnerRel.contact:roles[ ] + style membership.partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:membership.partnerRel.contact:OWNER[[membership.partnerRel.contact:OWNER]] + role:membership.partnerRel.contact:ADMIN[[membership.partnerRel.contact:ADMIN]] + role:membership.partnerRel.contact:REFERRER[[membership.partnerRel.contact:REFERRER]] + end + end + + subgraph membership.partnerRel.holderPerson["`**membership.partnerRel.holderPerson**`"] + direction TB + style membership.partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership.partnerRel.holderPerson:roles[ ] + style membership.partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:membership.partnerRel.holderPerson:OWNER[[membership.partnerRel.holderPerson:OWNER]] + role:membership.partnerRel.holderPerson:ADMIN[[membership.partnerRel.holderPerson:ADMIN]] + role:membership.partnerRel.holderPerson:REFERRER[[membership.partnerRel.holderPerson:REFERRER]] + end + end + + %% granting roles to roles + role:rbac.global:ADMIN -.-> role:membership.partnerRel.anchorPerson:OWNER + role:membership.partnerRel.anchorPerson:OWNER -.-> role:membership.partnerRel.anchorPerson:ADMIN + role:membership.partnerRel.anchorPerson:ADMIN -.-> role:membership.partnerRel.anchorPerson:REFERRER + role:rbac.global:ADMIN -.-> role:membership.partnerRel.holderPerson:OWNER + role:membership.partnerRel.holderPerson:OWNER -.-> role:membership.partnerRel.holderPerson:ADMIN + role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel.holderPerson:REFERRER + role:rbac.global:ADMIN -.-> role:membership.partnerRel.contact:OWNER + role:membership.partnerRel.contact:OWNER -.-> role:membership.partnerRel.contact:ADMIN + role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel.contact:REFERRER + role:rbac.global:ADMIN -.-> role:membership.partnerRel:OWNER + role:membership.partnerRel:OWNER -.-> role:membership.partnerRel:ADMIN + role:membership.partnerRel:ADMIN -.-> role:membership.partnerRel:AGENT + role:membership.partnerRel:AGENT -.-> role:membership.partnerRel:TENANT + role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel:TENANT + role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.anchorPerson:REFERRER + role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.holderPerson:REFERRER + role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.contact:REFERRER + role:membership.partnerRel.anchorPerson:ADMIN -.-> role:membership.partnerRel:OWNER + role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel:AGENT + role:membership:OWNER -.-> role:membership:ADMIN + role:membership.partnerRel:ADMIN -.-> role:membership:ADMIN + role:membership:ADMIN -.-> role:membership:AGENT + role:membership.partnerRel:AGENT -.-> role:membership:AGENT + role:membership:AGENT -.-> role:membership.partnerRel:TENANT + + %% granting permissions to roles + role:membership:ADMIN ==> perm:coopAssetsTransaction:INSERT + role:membership:ADMIN ==> perm:coopAssetsTransaction:UPDATE + role:membership:AGENT ==> perm:coopAssetsTransaction:SELECT + """); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntityUnitTest.java index 08a2718d..6d15cb78 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntityUnitTest.java @@ -1,5 +1,6 @@ package net.hostsharing.hsadminng.hs.office.coopshares; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import java.time.LocalDate; @@ -67,4 +68,123 @@ class HsOfficeCoopSharesTransactionEntityUnitTest { assertThat(result).isEqualTo("null:nul:+0"); } + + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficeCoopSharesTransactionEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph coopSharesTransaction["`**coopSharesTransaction**`"] + direction TB + style coopSharesTransaction fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph coopSharesTransaction:permissions[ ] + style coopSharesTransaction:permissions fill:#dd4901,stroke:white + + perm:coopSharesTransaction:INSERT{{coopSharesTransaction:INSERT}} + perm:coopSharesTransaction:UPDATE{{coopSharesTransaction:UPDATE}} + perm:coopSharesTransaction:SELECT{{coopSharesTransaction:SELECT}} + end + end + + subgraph membership["`**membership**`"] + direction TB + style membership fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership:roles[ ] + style membership:roles fill:#99bcdb,stroke:white + + role:membership:OWNER[[membership:OWNER]] + role:membership:ADMIN[[membership:ADMIN]] + role:membership:AGENT[[membership:AGENT]] + end + end + + subgraph membership.partnerRel["`**membership.partnerRel**`"] + direction TB + style membership.partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership.partnerRel:roles[ ] + style membership.partnerRel:roles fill:#99bcdb,stroke:white + + role:membership.partnerRel:OWNER[[membership.partnerRel:OWNER]] + role:membership.partnerRel:ADMIN[[membership.partnerRel:ADMIN]] + role:membership.partnerRel:AGENT[[membership.partnerRel:AGENT]] + role:membership.partnerRel:TENANT[[membership.partnerRel:TENANT]] + end + end + + subgraph membership.partnerRel.anchorPerson["`**membership.partnerRel.anchorPerson**`"] + direction TB + style membership.partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership.partnerRel.anchorPerson:roles[ ] + style membership.partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:membership.partnerRel.anchorPerson:OWNER[[membership.partnerRel.anchorPerson:OWNER]] + role:membership.partnerRel.anchorPerson:ADMIN[[membership.partnerRel.anchorPerson:ADMIN]] + role:membership.partnerRel.anchorPerson:REFERRER[[membership.partnerRel.anchorPerson:REFERRER]] + end + end + + subgraph membership.partnerRel.contact["`**membership.partnerRel.contact**`"] + direction TB + style membership.partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership.partnerRel.contact:roles[ ] + style membership.partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:membership.partnerRel.contact:OWNER[[membership.partnerRel.contact:OWNER]] + role:membership.partnerRel.contact:ADMIN[[membership.partnerRel.contact:ADMIN]] + role:membership.partnerRel.contact:REFERRER[[membership.partnerRel.contact:REFERRER]] + end + end + + subgraph membership.partnerRel.holderPerson["`**membership.partnerRel.holderPerson**`"] + direction TB + style membership.partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph membership.partnerRel.holderPerson:roles[ ] + style membership.partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:membership.partnerRel.holderPerson:OWNER[[membership.partnerRel.holderPerson:OWNER]] + role:membership.partnerRel.holderPerson:ADMIN[[membership.partnerRel.holderPerson:ADMIN]] + role:membership.partnerRel.holderPerson:REFERRER[[membership.partnerRel.holderPerson:REFERRER]] + end + end + + %% granting roles to roles + role:rbac.global:ADMIN -.-> role:membership.partnerRel.anchorPerson:OWNER + role:membership.partnerRel.anchorPerson:OWNER -.-> role:membership.partnerRel.anchorPerson:ADMIN + role:membership.partnerRel.anchorPerson:ADMIN -.-> role:membership.partnerRel.anchorPerson:REFERRER + role:rbac.global:ADMIN -.-> role:membership.partnerRel.holderPerson:OWNER + role:membership.partnerRel.holderPerson:OWNER -.-> role:membership.partnerRel.holderPerson:ADMIN + role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel.holderPerson:REFERRER + role:rbac.global:ADMIN -.-> role:membership.partnerRel.contact:OWNER + role:membership.partnerRel.contact:OWNER -.-> role:membership.partnerRel.contact:ADMIN + role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel.contact:REFERRER + role:rbac.global:ADMIN -.-> role:membership.partnerRel:OWNER + role:membership.partnerRel:OWNER -.-> role:membership.partnerRel:ADMIN + role:membership.partnerRel:ADMIN -.-> role:membership.partnerRel:AGENT + role:membership.partnerRel:AGENT -.-> role:membership.partnerRel:TENANT + role:membership.partnerRel.contact:ADMIN -.-> role:membership.partnerRel:TENANT + role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.anchorPerson:REFERRER + role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.holderPerson:REFERRER + role:membership.partnerRel:TENANT -.-> role:membership.partnerRel.contact:REFERRER + role:membership.partnerRel.anchorPerson:ADMIN -.-> role:membership.partnerRel:OWNER + role:membership.partnerRel.holderPerson:ADMIN -.-> role:membership.partnerRel:AGENT + role:membership:OWNER -.-> role:membership:ADMIN + role:membership.partnerRel:ADMIN -.-> role:membership:ADMIN + role:membership:ADMIN -.-> role:membership:AGENT + role:membership.partnerRel:AGENT -.-> role:membership:AGENT + role:membership:AGENT -.-> role:membership.partnerRel:TENANT + + %% granting permissions to roles + role:membership:ADMIN ==> perm:coopSharesTransaction:INSERT + role:membership:ADMIN ==> perm:coopSharesTransaction:UPDATE + role:membership:AGENT ==> perm:coopSharesTransaction:SELECT + """); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityUnitTest.java index 5dc61235..f11856d4 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorEntityUnitTest.java @@ -5,6 +5,8 @@ import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; +import net.hostsharing.hsadminng.rbac.test.cust.TestCustomerEntity; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -109,4 +111,200 @@ class HsOfficeDebitorEntityUnitTest { assertThat(result).isNull(); } + + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficeDebitorEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph debitor["`**debitor**`"] + direction TB + style debitor fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph debitor:permissions[ ] + style debitor:permissions fill:#dd4901,stroke:white + + perm:debitor:INSERT{{debitor:INSERT}} + perm:debitor:DELETE{{debitor:DELETE}} + perm:debitor:UPDATE{{debitor:UPDATE}} + perm:debitor:SELECT{{debitor:SELECT}} + end + + subgraph debitorRel["`**debitorRel**`"] + direction TB + style debitorRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel:roles[ ] + style debitorRel:roles fill:#99bcdb,stroke:white + + role:debitorRel:OWNER[[debitorRel:OWNER]] + role:debitorRel:ADMIN[[debitorRel:ADMIN]] + role:debitorRel:AGENT[[debitorRel:AGENT]] + role:debitorRel:TENANT[[debitorRel:TENANT]] + end + end + end + + subgraph debitorRel.anchorPerson["`**debitorRel.anchorPerson**`"] + direction TB + style debitorRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.anchorPerson:roles[ ] + style debitorRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.anchorPerson:OWNER[[debitorRel.anchorPerson:OWNER]] + role:debitorRel.anchorPerson:ADMIN[[debitorRel.anchorPerson:ADMIN]] + role:debitorRel.anchorPerson:REFERRER[[debitorRel.anchorPerson:REFERRER]] + end + end + + subgraph debitorRel.contact["`**debitorRel.contact**`"] + direction TB + style debitorRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.contact:roles[ ] + style debitorRel.contact:roles fill:#99bcdb,stroke:white + + role:debitorRel.contact:OWNER[[debitorRel.contact:OWNER]] + role:debitorRel.contact:ADMIN[[debitorRel.contact:ADMIN]] + role:debitorRel.contact:REFERRER[[debitorRel.contact:REFERRER]] + end + end + + subgraph debitorRel.holderPerson["`**debitorRel.holderPerson**`"] + direction TB + style debitorRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.holderPerson:roles[ ] + style debitorRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.holderPerson:OWNER[[debitorRel.holderPerson:OWNER]] + role:debitorRel.holderPerson:ADMIN[[debitorRel.holderPerson:ADMIN]] + role:debitorRel.holderPerson:REFERRER[[debitorRel.holderPerson:REFERRER]] + end + end + + subgraph partnerRel["`**partnerRel**`"] + direction TB + style partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel:roles[ ] + style partnerRel:roles fill:#99bcdb,stroke:white + + role:partnerRel:OWNER[[partnerRel:OWNER]] + role:partnerRel:ADMIN[[partnerRel:ADMIN]] + role:partnerRel:AGENT[[partnerRel:AGENT]] + role:partnerRel:TENANT[[partnerRel:TENANT]] + end + end + + subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:OWNER[[partnerRel.anchorPerson:OWNER]] + role:partnerRel.anchorPerson:ADMIN[[partnerRel.anchorPerson:ADMIN]] + role:partnerRel.anchorPerson:REFERRER[[partnerRel.anchorPerson:REFERRER]] + end + end + + subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:OWNER[[partnerRel.contact:OWNER]] + role:partnerRel.contact:ADMIN[[partnerRel.contact:ADMIN]] + role:partnerRel.contact:REFERRER[[partnerRel.contact:REFERRER]] + end + end + + subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:OWNER[[partnerRel.holderPerson:OWNER]] + role:partnerRel.holderPerson:ADMIN[[partnerRel.holderPerson:ADMIN]] + role:partnerRel.holderPerson:REFERRER[[partnerRel.holderPerson:REFERRER]] + end + end + + subgraph refundBankAccount["`**refundBankAccount**`"] + direction TB + style refundBankAccount fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph refundBankAccount:roles[ ] + style refundBankAccount:roles fill:#99bcdb,stroke:white + + role:refundBankAccount:OWNER[[refundBankAccount:OWNER]] + role:refundBankAccount:ADMIN[[refundBankAccount:ADMIN]] + role:refundBankAccount:REFERRER[[refundBankAccount:REFERRER]] + end + end + + %% granting roles to roles + role:rbac.global:ADMIN -.-> role:debitorRel.anchorPerson:OWNER + role:debitorRel.anchorPerson:OWNER -.-> role:debitorRel.anchorPerson:ADMIN + role:debitorRel.anchorPerson:ADMIN -.-> role:debitorRel.anchorPerson:REFERRER + role:rbac.global:ADMIN -.-> role:debitorRel.holderPerson:OWNER + role:debitorRel.holderPerson:OWNER -.-> role:debitorRel.holderPerson:ADMIN + role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel.holderPerson:REFERRER + role:rbac.global:ADMIN -.-> role:debitorRel.contact:OWNER + role:debitorRel.contact:OWNER -.-> role:debitorRel.contact:ADMIN + role:debitorRel.contact:ADMIN -.-> role:debitorRel.contact:REFERRER + role:rbac.global:ADMIN -.-> role:debitorRel:OWNER + role:debitorRel:OWNER -.-> role:debitorRel:ADMIN + role:debitorRel:ADMIN -.-> role:debitorRel:AGENT + role:debitorRel:AGENT -.-> role:debitorRel:TENANT + role:debitorRel.contact:ADMIN -.-> role:debitorRel:TENANT + role:debitorRel:TENANT -.-> role:debitorRel.anchorPerson:REFERRER + role:debitorRel:TENANT -.-> role:debitorRel.holderPerson:REFERRER + role:debitorRel:TENANT -.-> role:debitorRel.contact:REFERRER + role:debitorRel.anchorPerson:ADMIN -.-> role:debitorRel:OWNER + role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel:AGENT + role:rbac.global:ADMIN -.-> role:refundBankAccount:OWNER + role:refundBankAccount:OWNER -.-> role:refundBankAccount:ADMIN + role:refundBankAccount:ADMIN -.-> role:refundBankAccount:REFERRER + role:refundBankAccount:ADMIN ==> role:debitorRel:AGENT + role:debitorRel:AGENT ==> role:refundBankAccount:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel.anchorPerson:OWNER + role:partnerRel.anchorPerson:OWNER -.-> role:partnerRel.anchorPerson:ADMIN + role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel.anchorPerson:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel.holderPerson:OWNER + role:partnerRel.holderPerson:OWNER -.-> role:partnerRel.holderPerson:ADMIN + role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel.holderPerson:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel.contact:OWNER + role:partnerRel.contact:OWNER -.-> role:partnerRel.contact:ADMIN + role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel:OWNER + role:partnerRel:OWNER -.-> role:partnerRel:ADMIN + role:partnerRel:ADMIN -.-> role:partnerRel:AGENT + role:partnerRel:AGENT -.-> role:partnerRel:TENANT + role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT + role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER + role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER + role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER + role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:OWNER + role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT + role:partnerRel:ADMIN ==> role:debitorRel:ADMIN + role:partnerRel:AGENT ==> role:debitorRel:AGENT + role:debitorRel:AGENT ==> role:partnerRel:TENANT + + %% granting permissions to roles + role:rbac.global:ADMIN ==> perm:debitor:INSERT + role:debitorRel:OWNER ==> perm:debitor:DELETE + role:debitorRel:ADMIN ==> perm:debitor:UPDATE + role:debitorRel:TENANT ==> perm:debitor:SELECT + """); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityUnitTest.java index b2e5bb68..bd65db75 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntityUnitTest.java @@ -1,7 +1,9 @@ package net.hostsharing.hsadminng.hs.office.membership; import io.hypersistence.utils.hibernate.type.range.Range; +import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import jakarta.persistence.PrePersist; @@ -98,7 +100,126 @@ class HsOfficeMembershipEntityUnitTest { givenMembership.setValidTo(LocalDate.parse("2024-12-31")); assertThat(givenMembership.getValidFrom()).isEqualTo(GIVEN_VALID_FROM); assertThat(givenMembership.getValidTo()).isEqualTo(LocalDate.parse("2024-12-31")); + } + + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficeMembershipEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph membership["`**membership**`"] + direction TB + style membership fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph membership:roles[ ] + style membership:roles fill:#dd4901,stroke:white + + role:membership:OWNER[[membership:OWNER]] + role:membership:ADMIN[[membership:ADMIN]] + role:membership:AGENT[[membership:AGENT]] + end + + subgraph membership:permissions[ ] + style membership:permissions fill:#dd4901,stroke:white + + perm:membership:INSERT{{membership:INSERT}} + perm:membership:DELETE{{membership:DELETE}} + perm:membership:UPDATE{{membership:UPDATE}} + perm:membership:SELECT{{membership:SELECT}} + end + end + + subgraph partnerRel["`**partnerRel**`"] + direction TB + style partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel:roles[ ] + style partnerRel:roles fill:#99bcdb,stroke:white + + role:partnerRel:OWNER[[partnerRel:OWNER]] + role:partnerRel:ADMIN[[partnerRel:ADMIN]] + role:partnerRel:AGENT[[partnerRel:AGENT]] + role:partnerRel:TENANT[[partnerRel:TENANT]] + end + end + + subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:OWNER[[partnerRel.anchorPerson:OWNER]] + role:partnerRel.anchorPerson:ADMIN[[partnerRel.anchorPerson:ADMIN]] + role:partnerRel.anchorPerson:REFERRER[[partnerRel.anchorPerson:REFERRER]] + end + end + + subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:OWNER[[partnerRel.contact:OWNER]] + role:partnerRel.contact:ADMIN[[partnerRel.contact:ADMIN]] + role:partnerRel.contact:REFERRER[[partnerRel.contact:REFERRER]] + end + end + + subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:OWNER[[partnerRel.holderPerson:OWNER]] + role:partnerRel.holderPerson:ADMIN[[partnerRel.holderPerson:ADMIN]] + role:partnerRel.holderPerson:REFERRER[[partnerRel.holderPerson:REFERRER]] + end + end + + %% granting roles to users + user:creator ==> role:membership:OWNER + + %% granting roles to roles + role:rbac.global:ADMIN -.-> role:partnerRel.anchorPerson:OWNER + role:partnerRel.anchorPerson:OWNER -.-> role:partnerRel.anchorPerson:ADMIN + role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel.anchorPerson:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel.holderPerson:OWNER + role:partnerRel.holderPerson:OWNER -.-> role:partnerRel.holderPerson:ADMIN + role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel.holderPerson:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel.contact:OWNER + role:partnerRel.contact:OWNER -.-> role:partnerRel.contact:ADMIN + role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel:OWNER + role:partnerRel:OWNER -.-> role:partnerRel:ADMIN + role:partnerRel:ADMIN -.-> role:partnerRel:AGENT + role:partnerRel:AGENT -.-> role:partnerRel:TENANT + role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT + role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER + role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER + role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER + role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:OWNER + role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT + role:membership:OWNER ==> role:membership:ADMIN + role:partnerRel:ADMIN ==> role:membership:ADMIN + role:membership:ADMIN ==> role:membership:AGENT + role:partnerRel:AGENT ==> role:membership:AGENT + role:membership:AGENT ==> role:partnerRel:TENANT + + %% granting permissions to roles + role:rbac.global:ADMIN ==> perm:membership:INSERT + role:membership:ADMIN ==> perm:membership:DELETE + role:membership:ADMIN ==> perm:membership:UPDATE + role:membership:AGENT ==> perm:membership:SELECT + """); } private static void invokePrePersist(final HsOfficeMembershipEntity membershipEntity) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityUnitTest.java index 3cf07cab..33c83df7 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityUnitTest.java @@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -38,4 +39,123 @@ class HsOfficePartnerEntityUnitTest { final var result = givenPartner.toShortString(); assertThat(result).isEqualTo("P-12345"); } + + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficePartnerEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph partner["`**partner**`"] + direction TB + style partner fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph partner:permissions[ ] + style partner:permissions fill:#dd4901,stroke:white + + perm:partner:INSERT{{partner:INSERT}} + perm:partner:DELETE{{partner:DELETE}} + perm:partner:UPDATE{{partner:UPDATE}} + perm:partner:SELECT{{partner:SELECT}} + end + + subgraph partnerRel["`**partnerRel**`"] + direction TB + style partnerRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel:roles[ ] + style partnerRel:roles fill:#99bcdb,stroke:white + + role:partnerRel:OWNER[[partnerRel:OWNER]] + role:partnerRel:ADMIN[[partnerRel:ADMIN]] + role:partnerRel:AGENT[[partnerRel:AGENT]] + role:partnerRel:TENANT[[partnerRel:TENANT]] + end + end + end + + subgraph partnerDetails["`**partnerDetails**`"] + direction TB + style partnerDetails fill:#feb28c,stroke:#274d6e,stroke-width:8px + + subgraph partnerDetails:permissions[ ] + style partnerDetails:permissions fill:#feb28c,stroke:white + + perm:partnerDetails:DELETE{{partnerDetails:DELETE}} + perm:partnerDetails:UPDATE{{partnerDetails:UPDATE}} + perm:partnerDetails:SELECT{{partnerDetails:SELECT}} + end + end + + subgraph partnerRel.anchorPerson["`**partnerRel.anchorPerson**`"] + direction TB + style partnerRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.anchorPerson:roles[ ] + style partnerRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.anchorPerson:OWNER[[partnerRel.anchorPerson:OWNER]] + role:partnerRel.anchorPerson:ADMIN[[partnerRel.anchorPerson:ADMIN]] + role:partnerRel.anchorPerson:REFERRER[[partnerRel.anchorPerson:REFERRER]] + end + end + + subgraph partnerRel.contact["`**partnerRel.contact**`"] + direction TB + style partnerRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.contact:roles[ ] + style partnerRel.contact:roles fill:#99bcdb,stroke:white + + role:partnerRel.contact:OWNER[[partnerRel.contact:OWNER]] + role:partnerRel.contact:ADMIN[[partnerRel.contact:ADMIN]] + role:partnerRel.contact:REFERRER[[partnerRel.contact:REFERRER]] + end + end + + subgraph partnerRel.holderPerson["`**partnerRel.holderPerson**`"] + direction TB + style partnerRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph partnerRel.holderPerson:roles[ ] + style partnerRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:partnerRel.holderPerson:OWNER[[partnerRel.holderPerson:OWNER]] + role:partnerRel.holderPerson:ADMIN[[partnerRel.holderPerson:ADMIN]] + role:partnerRel.holderPerson:REFERRER[[partnerRel.holderPerson:REFERRER]] + end + end + + %% granting roles to roles + role:rbac.global:ADMIN -.-> role:partnerRel.anchorPerson:OWNER + role:partnerRel.anchorPerson:OWNER -.-> role:partnerRel.anchorPerson:ADMIN + role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel.anchorPerson:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel.holderPerson:OWNER + role:partnerRel.holderPerson:OWNER -.-> role:partnerRel.holderPerson:ADMIN + role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel.holderPerson:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel.contact:OWNER + role:partnerRel.contact:OWNER -.-> role:partnerRel.contact:ADMIN + role:partnerRel.contact:ADMIN -.-> role:partnerRel.contact:REFERRER + role:rbac.global:ADMIN -.-> role:partnerRel:OWNER + role:partnerRel:OWNER -.-> role:partnerRel:ADMIN + role:partnerRel:ADMIN -.-> role:partnerRel:AGENT + role:partnerRel:AGENT -.-> role:partnerRel:TENANT + role:partnerRel.contact:ADMIN -.-> role:partnerRel:TENANT + role:partnerRel:TENANT -.-> role:partnerRel.anchorPerson:REFERRER + role:partnerRel:TENANT -.-> role:partnerRel.holderPerson:REFERRER + role:partnerRel:TENANT -.-> role:partnerRel.contact:REFERRER + role:partnerRel.anchorPerson:ADMIN -.-> role:partnerRel:OWNER + role:partnerRel.holderPerson:ADMIN -.-> role:partnerRel:AGENT + + %% granting permissions to roles + role:rbac.global:ADMIN ==> perm:partner:INSERT + role:partnerRel:OWNER ==> perm:partner:DELETE + role:partnerRel:ADMIN ==> perm:partner:UPDATE + role:partnerRel:TENANT ==> perm:partner:SELECT + role:partnerRel:OWNER ==> perm:partnerDetails:DELETE + role:partnerRel:AGENT ==> perm:partnerDetails:UPDATE + role:partnerRel:AGENT ==> perm:partnerDetails:SELECT + """); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntityUnitTest.java index 199e7f23..f015b10e 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntityUnitTest.java @@ -1,5 +1,7 @@ package net.hostsharing.hsadminng.hs.office.person; +import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import java.util.UUID; @@ -155,6 +157,7 @@ class HsOfficePersonEntityUnitTest { assertThat(actualDisplay).isEqualTo("person(salutation='Herr', familyName='some family name', givenName='some given name')"); } + @Test void toStringWithoutSalutationAndWithTitleSkipsSalutation() { final var givenPersonEntity = HsOfficePersonEntity.builder() @@ -168,4 +171,48 @@ class HsOfficePersonEntityUnitTest { assertThat(actualDisplay).isEqualTo("person(title='some title', familyName='some family name', givenName='some given name')"); } + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficePersonEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{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:rbac.global:ADMIN ==> role:person:OWNER + role:person:OWNER ==> role:person:ADMIN + role:person:ADMIN ==> role:person:REFERRER + + %% granting permissions to roles + role:rbac.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/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationUnitTest.java index a422a8b6..96ebc37c 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relation/HsOfficeRelationUnitTest.java @@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.hs.office.relation; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -40,4 +41,103 @@ class HsOfficeRelationUnitTest { assertThat(given.toShortString()).isEqualTo("rel(anchor='LP some trade name', type='REPRESENTATIVE', holder='NP Meier, Mellie')"); } + + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficeRelationRbacEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph anchorPerson["`**anchorPerson**`"] + direction TB + 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 contact["`**contact**`"] + direction TB + 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 holderPerson["`**holderPerson**`"] + direction TB + 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 relation["`**relation**`"] + direction TB + style relation fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph relation:roles[ ] + style relation:roles fill:#dd4901,stroke:white + + role:relation:OWNER[[relation:OWNER]] + role:relation:ADMIN[[relation:ADMIN]] + role:relation:AGENT[[relation:AGENT]] + role:relation:TENANT[[relation:TENANT]] + end + + subgraph relation:permissions[ ] + style relation:permissions fill:#dd4901,stroke:white + + perm:relation:DELETE{{relation:DELETE}} + perm:relation:UPDATE{{relation:UPDATE}} + perm:relation:SELECT{{relation:SELECT}} + perm:relation:INSERT{{relation:INSERT}} + end + end + + %% granting roles to users + user:creator ==> role:relation:OWNER + + %% granting roles to roles + role:rbac.global:ADMIN -.-> role:anchorPerson:OWNER + role:anchorPerson:OWNER -.-> role:anchorPerson:ADMIN + role:anchorPerson:ADMIN -.-> role:anchorPerson:REFERRER + role:rbac.global:ADMIN -.-> role:holderPerson:OWNER + role:holderPerson:OWNER -.-> role:holderPerson:ADMIN + role:holderPerson:ADMIN -.-> role:holderPerson:REFERRER + role:rbac.global:ADMIN -.-> role:contact:OWNER + role:contact:OWNER -.-> role:contact:ADMIN + role:contact:ADMIN -.-> role:contact:REFERRER + role:rbac.global:ADMIN ==> role:relation:OWNER + role:relation:OWNER ==> role:relation:ADMIN + role:relation:ADMIN ==> role:relation:AGENT + role:relation:AGENT ==> role:relation:TENANT + role:contact:ADMIN ==> role:relation:TENANT + role:relation:TENANT ==> role:anchorPerson:REFERRER + role:relation:TENANT ==> role:holderPerson:REFERRER + role:relation:TENANT ==> role:contact:REFERRER + + %% granting permissions to roles + role:relation:OWNER ==> perm:relation:DELETE + role:relation:ADMIN ==> perm:relation:UPDATE + role:relation:TENANT ==> perm:relation:SELECT + role:anchorPerson:ADMIN ==> perm:relation:INSERT + """); + } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java index aaa40e7c..e3ca9feb 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java @@ -1,6 +1,8 @@ package net.hostsharing.hsadminng.hs.office.sepamandate; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; +import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRbacEntity; +import net.hostsharing.hsadminng.rbac.generator.RbacViewMermaidFlowchartGenerator; import org.junit.jupiter.api.Test; import java.time.LocalDate; @@ -49,4 +51,143 @@ class HsOfficeSepaMandateEntityUnitTest { assertThat(givenSepaMandate.getValidTo()).isEqualTo(LocalDate.parse("2024-12-31")); } + @Test + void definesRbac() { + final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(HsOfficeSepaMandateEntity.rbac()).toString(); + assertThat(rbacFlowchart).isEqualTo(""" + %%{init:{'flowchart':{'htmlLabels':false}}}%% + flowchart TB + + subgraph bankAccount["`**bankAccount**`"] + direction TB + style bankAccount fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph bankAccount:roles[ ] + style bankAccount:roles fill:#99bcdb,stroke:white + + role:bankAccount:OWNER[[bankAccount:OWNER]] + role:bankAccount:ADMIN[[bankAccount:ADMIN]] + role:bankAccount:REFERRER[[bankAccount:REFERRER]] + end + end + + subgraph debitorRel["`**debitorRel**`"] + direction TB + style debitorRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel:roles[ ] + style debitorRel:roles fill:#99bcdb,stroke:white + + role:debitorRel:OWNER[[debitorRel:OWNER]] + role:debitorRel:ADMIN[[debitorRel:ADMIN]] + role:debitorRel:AGENT[[debitorRel:AGENT]] + role:debitorRel:TENANT[[debitorRel:TENANT]] + end + end + + subgraph debitorRel.anchorPerson["`**debitorRel.anchorPerson**`"] + direction TB + style debitorRel.anchorPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.anchorPerson:roles[ ] + style debitorRel.anchorPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.anchorPerson:OWNER[[debitorRel.anchorPerson:OWNER]] + role:debitorRel.anchorPerson:ADMIN[[debitorRel.anchorPerson:ADMIN]] + role:debitorRel.anchorPerson:REFERRER[[debitorRel.anchorPerson:REFERRER]] + end + end + + subgraph debitorRel.contact["`**debitorRel.contact**`"] + direction TB + style debitorRel.contact fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.contact:roles[ ] + style debitorRel.contact:roles fill:#99bcdb,stroke:white + + role:debitorRel.contact:OWNER[[debitorRel.contact:OWNER]] + role:debitorRel.contact:ADMIN[[debitorRel.contact:ADMIN]] + role:debitorRel.contact:REFERRER[[debitorRel.contact:REFERRER]] + end + end + + subgraph debitorRel.holderPerson["`**debitorRel.holderPerson**`"] + direction TB + style debitorRel.holderPerson fill:#99bcdb,stroke:#274d6e,stroke-width:8px + + subgraph debitorRel.holderPerson:roles[ ] + style debitorRel.holderPerson:roles fill:#99bcdb,stroke:white + + role:debitorRel.holderPerson:OWNER[[debitorRel.holderPerson:OWNER]] + role:debitorRel.holderPerson:ADMIN[[debitorRel.holderPerson:ADMIN]] + role:debitorRel.holderPerson:REFERRER[[debitorRel.holderPerson:REFERRER]] + end + end + + subgraph sepaMandate["`**sepaMandate**`"] + direction TB + style sepaMandate fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph sepaMandate:roles[ ] + style sepaMandate:roles fill:#dd4901,stroke:white + + role:sepaMandate:OWNER[[sepaMandate:OWNER]] + role:sepaMandate:ADMIN[[sepaMandate:ADMIN]] + role:sepaMandate:AGENT[[sepaMandate:AGENT]] + role:sepaMandate:REFERRER[[sepaMandate:REFERRER]] + end + + subgraph sepaMandate:permissions[ ] + style sepaMandate:permissions fill:#dd4901,stroke:white + + perm:sepaMandate:DELETE{{sepaMandate:DELETE}} + perm:sepaMandate:UPDATE{{sepaMandate:UPDATE}} + perm:sepaMandate:SELECT{{sepaMandate:SELECT}} + perm:sepaMandate:INSERT{{sepaMandate:INSERT}} + end + end + + %% granting roles to users + user:creator ==> role:sepaMandate:OWNER + + %% granting roles to roles + role:rbac.global:ADMIN -.-> role:debitorRel.anchorPerson:OWNER + role:debitorRel.anchorPerson:OWNER -.-> role:debitorRel.anchorPerson:ADMIN + role:debitorRel.anchorPerson:ADMIN -.-> role:debitorRel.anchorPerson:REFERRER + role:rbac.global:ADMIN -.-> role:debitorRel.holderPerson:OWNER + role:debitorRel.holderPerson:OWNER -.-> role:debitorRel.holderPerson:ADMIN + role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel.holderPerson:REFERRER + role:rbac.global:ADMIN -.-> role:debitorRel.contact:OWNER + role:debitorRel.contact:OWNER -.-> role:debitorRel.contact:ADMIN + role:debitorRel.contact:ADMIN -.-> role:debitorRel.contact:REFERRER + role:rbac.global:ADMIN -.-> role:debitorRel:OWNER + role:debitorRel:OWNER -.-> role:debitorRel:ADMIN + role:debitorRel:ADMIN -.-> role:debitorRel:AGENT + role:debitorRel:AGENT -.-> role:debitorRel:TENANT + role:debitorRel.contact:ADMIN -.-> role:debitorRel:TENANT + role:debitorRel:TENANT -.-> role:debitorRel.anchorPerson:REFERRER + role:debitorRel:TENANT -.-> role:debitorRel.holderPerson:REFERRER + role:debitorRel:TENANT -.-> role:debitorRel.contact:REFERRER + role:debitorRel.anchorPerson:ADMIN -.-> role:debitorRel:OWNER + role:debitorRel.holderPerson:ADMIN -.-> role:debitorRel:AGENT + role:rbac.global:ADMIN -.-> role:bankAccount:OWNER + role:bankAccount:OWNER -.-> role:bankAccount:ADMIN + role:bankAccount:ADMIN -.-> role:bankAccount:REFERRER + role:rbac.global:ADMIN ==> role:sepaMandate:OWNER + role:sepaMandate:OWNER ==> role:sepaMandate:ADMIN + role:sepaMandate:ADMIN ==> role:sepaMandate:AGENT + role:sepaMandate:AGENT ==> role:bankAccount:REFERRER + role:sepaMandate:AGENT ==> role:debitorRel:AGENT + role:sepaMandate:AGENT ==> role:sepaMandate:REFERRER + role:bankAccount:ADMIN ==> role:sepaMandate:REFERRER + role:debitorRel:AGENT ==> role:sepaMandate:REFERRER + role:sepaMandate:REFERRER ==> role:debitorRel:TENANT + + %% granting permissions to roles + role:sepaMandate:OWNER ==> perm:sepaMandate:DELETE + role:sepaMandate:ADMIN ==> perm:sepaMandate:UPDATE + role:sepaMandate:REFERRER ==> perm:sepaMandate:SELECT + role:debitorRel:ADMIN ==> perm:sepaMandate:INSERT + """); + } }