add allGrantsFrom to RbacGrantsMermaidService

This commit is contained in:
Michael Hoennig 2024-02-14 11:10:21 +01:00
parent 188f5677f5
commit 5d9e81630b
3 changed files with 104 additions and 67 deletions

View File

@ -10,4 +10,6 @@ public interface RawRbacGrantRepository extends Repository<RawRbacGrantEntity, U
List<RawRbacGrantEntity> findAll();
List<RawRbacGrantEntity> findByAscendingUuid(UUID ascendingUuid);
List<RawRbacGrantEntity> findByDescendantUuid(UUID refUuid);
}

View File

@ -4,10 +4,10 @@ import net.hostsharing.hsadminng.context.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.UUID;
import java.util.*;
import static net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsMermaidService.Include.*;
@ -15,6 +15,7 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsMermaidService.
public class RbacGrantsMermaidService {
public enum Include {
USERS,
PERMISSIONS,
NOT_ASSUMED,
TEST_ENTITIES,
@ -27,15 +28,18 @@ public class RbacGrantsMermaidService {
@Autowired
private RawRbacGrantRepository rawGrantRepo;
@PersistenceContext
private EntityManager em;
public String allGrantsToCurrentUser(final EnumSet<Include> include) {
final var graph = new ArrayList<String>();
final var graph = new HashSet<String>();
for ( UUID subjectUuid: context.currentSubjectsUuids() ) {
traverseGrantsTo(graph, subjectUuid, include);
}
return "flowchart TB\n\n" + String.join("\n", graph);
}
private void traverseGrantsTo(final ArrayList<String> graph, final UUID refUuid, final EnumSet<Include> include) {
private void traverseGrantsTo(final Set<String> graph, final UUID refUuid, final EnumSet<Include> include) {
final var grants = rawGrantRepo.findByAscendingUuid(refUuid);
grants.forEach(g -> {
if (!include.contains(PERMISSIONS) && g.getDescendantIdName().startsWith("perm ")) {
@ -57,25 +61,51 @@ public class RbacGrantsMermaidService {
});
}
public String allGrantsFrom(final UUID targetObject, final String op, final EnumSet<Include> include) {
final var refUuid = (UUID) em.createNativeQuery("SELECT uuid FROM rbacpermission WHERE objectuuid=:targetObject AND op=:op")
.setParameter("targetObject", targetObject)
.setParameter("op", op)
.getSingleResult();
final var graph = new HashSet<String>();
traverseGrantsFrom(graph, refUuid, include);
return "flowchart TB\n\n" + String.join("\n", graph);
}
private void traverseGrantsFrom(final Set<String> graph, final UUID refUuid, final EnumSet<Include> include) {
final var grants = rawGrantRepo.findByDescendantUuid(refUuid);
grants.forEach(g -> {
if (!include.contains(USERS) && g.getAscendantIdName().startsWith("user ")) {
return;
}
graph.add(
node(g.getAscendantIdName()) +
(g.isAssumed() ? " --> " : " -.-> ") +
node(g.getDescendantIdName()));
if (include.contains(NOT_ASSUMED) || g.isAssumed()) {
traverseGrantsFrom(graph, g.getAscendingUuid(), include);
}
});
}
private String node(final String idName) {
if (idName.contains("@")) {
return quoted(idName).replaceAll("@.*", "") + "[" + quoted(idName) + "]";
}
return quoted(idName) + display(idName);
}
private String display(final String idName) {
// role hs_office_relationship#FirstGmbH-with-REPRESENTATIVE-FirbySusan.admin
// TODO: refactor by separate algorithms for perm/role/user
final var refType = idName.split(" ", 2)[0];
final var roleType = refType.equals("perm")
final var roleType = refType.equals("role")
? idName.substring(idName.lastIndexOf('.') + 1)
: refType.equals("perm")
? idName.split(" ")[1]
: idName.substring(idName.lastIndexOf('.') + 1);
: null;
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;
: idName.substring(refType.length()+1, idName.length() - (roleType == null ? 0 : (roleType.length()-1)) );
final var tableName = objectName.contains("#") ? objectName.split("#")[0] : "";
final var instanceName = objectName.contains("#") ? objectName.split("#", 2)[1] : objectName;
final var displayName = "\n" + tableName + "\n" + instanceName + (roleType == null ? "" : ("\n" + roleType));
if (refType.equals("user")) {
return "(" + displayName + ")";
}
@ -90,6 +120,6 @@ public class RbacGrantsMermaidService {
@NotNull
private static String quoted(final String idName) {
return idName.replace(" ", ":");
return idName.replace(" ", ":").replaceAll("@.*", "");
}
}

View File

@ -16,6 +16,7 @@ import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.EnumSet;
import java.util.UUID;
import static java.lang.String.join;
import static org.assertj.core.api.Assertions.assertThat;
@ -37,27 +38,27 @@ class RbacGrantsMermaidServiceIntegrationTest extends ContextBasedTestWithCleanu
assertThat(graph).isEqualTo("""
flowchart TB
role:test_package#xxx00.tenant[
test_package
xxx00.t
tenant] --> role:test_customer#xxx.tenant[
test_customer
xxx.t
tenant]
role:test_domain#xxx00-aaaa.owner[
test_domain
xxx00-aaaa
xxx00-aaaa.o
owner] --> role:test_domain#xxx00-aaaa.admin[
test_domain
xxx00-aaaa
xxx00-aaaa.a
admin]
role:test_domain#xxx00-aaaa.admin[
test_domain
xxx00-aaaa
xxx00-aaaa.a
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
xxx00.t
tenant]
""".trim());
}
@ -69,56 +70,56 @@ class RbacGrantsMermaidServiceIntegrationTest extends ContextBasedTestWithCleanu
assertThat(graph).isEqualTo("""
flowchart TB
role:test_domain#xxx00-aaaa.owner[
test_domain
xxx00-aaaa
xxx00-aaaa.o
owner] --> perm:*:on:test_domain#xxx00-aaaa{{
test_domain
xxx00-aaaa
*}}
role:test_domain#xxx00-aaaa.owner[
test_domain
xxx00-aaaa
owner] --> role:test_domain#xxx00-aaaa.admin[
test_domain
xxx00-aaaa
admin]
role:test_domain#xxx00-aaaa.admin[
test_domain
xxx00-aaaa
admin] --> perm:edit:on:test_domain#xxx00-aaaa{{
test_domain
xxx00-aaaa
edit}}
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
xxx.t
tenant] --> perm:view:on:test_customer#xxx{{
test_customer
xxx
view}}
role:test_domain#xxx00-aaaa.admin[
test_domain
xxx00-aaaa.a
admin] --> perm:edit:on:test_domain#xxx00-aaaa{{
test_domain
xxx00-aaaa
edit}}
role:test_package#xxx00.tenant[
test_package
xxx00.t
tenant] --> role:test_customer#xxx.tenant[
test_customer
xxx.t
tenant]
role:test_domain#xxx00-aaaa.owner[
test_domain
xxx00-aaaa.o
owner] --> role:test_domain#xxx00-aaaa.admin[
test_domain
xxx00-aaaa.a
admin]
role:test_package#xxx00.tenant[
test_package
xxx00.t
tenant] --> perm:view:on:test_package#xxx00{{
test_package
xxx00
view}}
role:test_domain#xxx00-aaaa.admin[
test_domain
xxx00-aaaa.a
admin] --> role:test_package#xxx00.tenant[
test_package
xxx00.t
tenant]
""".trim());
}
@ -126,9 +127,13 @@ class RbacGrantsMermaidServiceIntegrationTest extends ContextBasedTestWithCleanu
@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");
context("superuser-alex@hostsharing.net");
//final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.NON_TEST_ENTITIES, Include.PERMISSIONS));
final var targetObject = (UUID) em.createNativeQuery("SELECT uuid FROM hs_office_coopassetstransaction WHERE reference='ref 1000101-1'").getSingleResult();
final var graph = grantsMermaidService.allGrantsFrom(targetObject, "view", EnumSet.of(Include.USERS));
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