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
+ """);
+ }
}