multi line node formatting in RbacGrantsMermaidService

This commit is contained in:
Michael Hoennig 2024-02-13 17:55:16 +01:00
parent 9c03e7441f
commit dee12b8f08
3 changed files with 128 additions and 42 deletions

View File

@ -29,7 +29,9 @@ public class RbacGrantsMermaidService {
public String allGrantsToCurrentUser(final EnumSet<Include> include) { public String allGrantsToCurrentUser(final EnumSet<Include> include) {
final var graph = new ArrayList<String>(); final var graph = new ArrayList<String>();
traverseGrantsTo(graph, context.getCurrentUserUUid(), include); for ( UUID subjectUuid: context.currentSubjectsUuids() ) {
traverseGrantsTo(graph, subjectUuid, include);
}
return "flowchart TB\n\n" + String.join("\n", graph); return "flowchart TB\n\n" + String.join("\n", graph);
} }
@ -46,20 +48,44 @@ public class RbacGrantsMermaidService {
return; return;
} }
graph.add( graph.add(
id(g.getAscendantIdName()) + node(g.getAscendantIdName()) +
(g.isAssumed() ? " --> " : " -.-> ") + (g.isAssumed() ? " --> " : " -.-> ") +
id(g.getDescendantIdName())); node(g.getDescendantIdName()));
if (include.contains(NOT_ASSUMED) || g.isAssumed()) { if (include.contains(NOT_ASSUMED) || g.isAssumed()) {
traverseGrantsTo(graph, g.getDescendantUuid(), include); traverseGrantsTo(graph, g.getDescendantUuid(), include);
} }
}); });
} }
private String id(final String idName) { private String node(final String idName) {
if (idName.contains("@")) { if (idName.contains("@")) {
return quoted(idName).replaceAll("@.*", "") + "[" + quoted(idName) + "]"; return quoted(idName).replaceAll("@.*", "") + "[" + quoted(idName) + "]";
} }
return quoted(idName); return quoted(idName) + display(idName);
}
private String display(final String idName) {
// role hs_office_relationship#FirstGmbH-with-REPRESENTATIVE-FirbySusan.admin
final var refType = idName.split(" ", 2)[0];
final var roleType = refType.equals("perm")
? idName.split(" ")[1]
: idName.substring(idName.lastIndexOf('.') + 1);
final var objectName = refType.equals("perm")
? idName.split(" ")[3]
: idName.substring(refType.length()+1, idName.length()-roleType.length()-1);
final var tableName = objectName.split("#")[0];
final var instanceName = objectName.split("#", 2)[1];
final var displayName = "\n" + tableName + "\n" + instanceName + "\n" + roleType;
if (refType.equals("user")) {
return "(" + displayName + ")";
}
if (refType.equals("role")) {
return "[" + displayName + "]";
}
if (refType.equals("perm")) {
return "{{" + displayName + "}}";
}
return "";
} }
@NotNull @NotNull

View File

@ -15,13 +15,13 @@ subgraph external[ ]
subgraph partnerPerson subgraph partnerPerson
style partnerPerson fill:#eee style partnerPerson fill:#eee
role:partnerPerson.admin[global.admin] role:partnerPerson.admin[partnerPerson.admin]
end end
subgraph otherRelatedPerson subgraph otherRelatedPerson
style otherRelatedPerson fill:#eee style otherRelatedPerson fill:#eee
role:otherRelatedPerson.admin[global.admin] role:otherRelatedPerson.admin[otherRelatedPerson.admin]
end end
subgraph hsOfficeRelationship[hsOfficeRelationship:PARTNER] subgraph hsOfficeRelationship[hsOfficeRelationship:PARTNER]

View File

@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsMermaidService.Include; import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsMermaidService.Include;
import net.hostsharing.test.JpaAttempt; import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
@ -11,8 +12,12 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.EnumSet; import java.util.EnumSet;
import static java.lang.String.join;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest @DataJpaTest
@ -27,56 +32,111 @@ class RbacGrantsMermaidServiceIntegrationTest extends ContextBasedTestWithCleanu
@Test @Test
void allGrantsToCurrentUser() { void allGrantsToCurrentUser() {
context("pac-admin-xxx00@xxx.example.com"); context("superuser-alex@hostsharing.net", "test_domain#xxx00-aaaa.owner");
final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.TEST_ENTITIES)); final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.TEST_ENTITIES));
assertThat(graph).isEqualTo(""" assertThat(graph).isEqualTo("""
flowchart TB flowchart TB
user:pac-admin-xxx00[user:pac-admin-xxx00@xxx.example.com] --> role:test_package#xxx00.admin role:test_domain#xxx00-aaaa.owner[
role:test_package#xxx00.admin --> role:test_domain#xxx00-aaaa.owner test_domain
role:test_domain#xxx00-aaaa.owner --> role:test_domain#xxx00-aaaa.admin xxx00-aaaa
role:test_domain#xxx00-aaaa.admin --> role:test_package#xxx00.tenant owner] --> role:test_domain#xxx00-aaaa.admin[
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant test_domain
role:test_package#xxx00.admin --> role:test_domain#xxx00-aaab.owner xxx00-aaaa
role:test_domain#xxx00-aaab.owner --> role:test_domain#xxx00-aaab.admin admin]
role:test_domain#xxx00-aaab.admin --> role:test_package#xxx00.tenant role:test_domain#xxx00-aaaa.admin[
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant test_domain
role:test_package#xxx00.admin --> role:test_package#xxx00.tenant xxx00-aaaa
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant admin] --> role:test_package#xxx00.tenant[
test_package
xxx00
tenant]
role:test_package#xxx00.tenant[
test_package
xxx00
tenant] --> role:test_customer#xxx.tenant[
test_customer
xxx
tenant]
""".trim()); """.trim());
} }
@Test @Test
void allGrantsToCurrentUserIncludingPermissions() { void allGrantsToCurrentUserIncludingPermissions() {
context("pac-admin-xxx00@xxx.example.com"); context("superuser-alex@hostsharing.net", "test_domain#xxx00-aaaa.owner");
final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.TEST_ENTITIES, Include.PERMISSIONS)); final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.TEST_ENTITIES, Include.PERMISSIONS));
assertThat(graph).isEqualTo(""" assertThat(graph).isEqualTo("""
flowchart TB flowchart TB
user:pac-admin-xxx00[user:pac-admin-xxx00@xxx.example.com] --> role:test_package#xxx00.admin role:test_domain#xxx00-aaaa.owner[
role:test_package#xxx00.admin --> perm:add-domain:on:test_package#xxx00 test_domain
role:test_package#xxx00.admin --> role:test_domain#xxx00-aaaa.owner xxx00-aaaa
role:test_domain#xxx00-aaaa.owner --> perm:*:on:test_domain#xxx00-aaaa owner] --> perm:*:on:test_domain#xxx00-aaaa{{
role:test_domain#xxx00-aaaa.owner --> role:test_domain#xxx00-aaaa.admin test_domain
role:test_domain#xxx00-aaaa.admin --> perm:edit:on:test_domain#xxx00-aaaa xxx00-aaaa
role:test_domain#xxx00-aaaa.admin --> role:test_package#xxx00.tenant *}}
role:test_package#xxx00.tenant --> perm:view:on:test_package#xxx00 role:test_domain#xxx00-aaaa.owner[
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant test_domain
role:test_customer#xxx.tenant --> perm:view:on:test_customer#xxx xxx00-aaaa
role:test_package#xxx00.admin --> role:test_domain#xxx00-aaab.owner owner] --> role:test_domain#xxx00-aaaa.admin[
role:test_domain#xxx00-aaab.owner --> perm:*:on:test_domain#xxx00-aaab test_domain
role:test_domain#xxx00-aaab.owner --> role:test_domain#xxx00-aaab.admin xxx00-aaaa
role:test_domain#xxx00-aaab.admin --> perm:edit:on:test_domain#xxx00-aaab admin]
role:test_domain#xxx00-aaab.admin --> role:test_package#xxx00.tenant role:test_domain#xxx00-aaaa.admin[
role:test_package#xxx00.tenant --> perm:view:on:test_package#xxx00 test_domain
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant xxx00-aaaa
role:test_customer#xxx.tenant --> perm:view:on:test_customer#xxx admin] --> perm:edit:on:test_domain#xxx00-aaaa{{
role:test_package#xxx00.admin --> role:test_package#xxx00.tenant test_domain
role:test_package#xxx00.tenant --> perm:view:on:test_package#xxx00 xxx00-aaaa
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant edit}}
role:test_customer#xxx.tenant --> perm:view:on:test_customer#xxx role:test_domain#xxx00-aaaa.admin[
test_domain
xxx00-aaaa
admin] --> role:test_package#xxx00.tenant[
test_package
xxx00
tenant]
role:test_package#xxx00.tenant[
test_package
xxx00
tenant] --> perm:view:on:test_package#xxx00{{
test_package
xxx00
view}}
role:test_package#xxx00.tenant[
test_package
xxx00
tenant] --> role:test_customer#xxx.tenant[
test_customer
xxx
tenant]
role:test_customer#xxx.tenant[
test_customer
xxx
tenant] --> perm:view:on:test_customer#xxx{{
test_customer
xxx
view}}
""".trim()); """.trim());
} }
@Test
@Disabled
void print() throws IOException {
//context("superuser-alex@hostsharing.net", "hs_office_person#FirbySusan.admin");
context("superuser-alex@hostsharing.net", "hs_office_person#FirstGmbH.admin");
final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.NON_TEST_ENTITIES, Include.PERMISSIONS));
try (BufferedWriter writer = new BufferedWriter(new FileWriter("doc/all-grants.md"))) {
writer.write("""
### all grants to %s
```mermaid
%s
```
""".formatted(join(";", context.getAssumedRoles()), graph));
}
}
} }