add allGrantsFrom to RbacGrantsMermaidService
This commit is contained in:
parent
188f5677f5
commit
5d9e81630b
@ -10,4 +10,6 @@ public interface RawRbacGrantRepository extends Repository<RawRbacGrantEntity, U
|
|||||||
List<RawRbacGrantEntity> findAll();
|
List<RawRbacGrantEntity> findAll();
|
||||||
|
|
||||||
List<RawRbacGrantEntity> findByAscendingUuid(UUID ascendingUuid);
|
List<RawRbacGrantEntity> findByAscendingUuid(UUID ascendingUuid);
|
||||||
|
|
||||||
|
List<RawRbacGrantEntity> findByDescendantUuid(UUID refUuid);
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,10 @@ import net.hostsharing.hsadminng.context.Context;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.PersistenceContext;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsMermaidService.Include.*;
|
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 class RbacGrantsMermaidService {
|
||||||
|
|
||||||
public enum Include {
|
public enum Include {
|
||||||
|
USERS,
|
||||||
PERMISSIONS,
|
PERMISSIONS,
|
||||||
NOT_ASSUMED,
|
NOT_ASSUMED,
|
||||||
TEST_ENTITIES,
|
TEST_ENTITIES,
|
||||||
@ -27,15 +28,18 @@ public class RbacGrantsMermaidService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private RawRbacGrantRepository rawGrantRepo;
|
private RawRbacGrantRepository rawGrantRepo;
|
||||||
|
|
||||||
|
@PersistenceContext
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
public String allGrantsToCurrentUser(final EnumSet<Include> include) {
|
public String allGrantsToCurrentUser(final EnumSet<Include> include) {
|
||||||
final var graph = new ArrayList<String>();
|
final var graph = new HashSet<String>();
|
||||||
for ( UUID subjectUuid: context.currentSubjectsUuids() ) {
|
for ( UUID subjectUuid: context.currentSubjectsUuids() ) {
|
||||||
traverseGrantsTo(graph, subjectUuid, include);
|
traverseGrantsTo(graph, subjectUuid, include);
|
||||||
}
|
}
|
||||||
return "flowchart TB\n\n" + String.join("\n", graph);
|
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);
|
final var grants = rawGrantRepo.findByAscendingUuid(refUuid);
|
||||||
grants.forEach(g -> {
|
grants.forEach(g -> {
|
||||||
if (!include.contains(PERMISSIONS) && g.getDescendantIdName().startsWith("perm ")) {
|
if (!include.contains(PERMISSIONS) && g.getDescendantIdName().startsWith("perm ")) {
|
||||||
@ -57,25 +61,51 @@ public class RbacGrantsMermaidService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private String node(final String idName) {
|
public String allGrantsFrom(final UUID targetObject, final String op, final EnumSet<Include> include) {
|
||||||
if (idName.contains("@")) {
|
final var refUuid = (UUID) em.createNativeQuery("SELECT uuid FROM rbacpermission WHERE objectuuid=:targetObject AND op=:op")
|
||||||
return quoted(idName).replaceAll("@.*", "") + "[" + quoted(idName) + "]";
|
.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) {
|
||||||
return quoted(idName) + display(idName);
|
return quoted(idName) + display(idName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String display(final String idName) {
|
private String display(final String idName) {
|
||||||
// role hs_office_relationship#FirstGmbH-with-REPRESENTATIVE-FirbySusan.admin
|
// 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 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.split(" ")[1]
|
||||||
: idName.substring(idName.lastIndexOf('.') + 1);
|
: null;
|
||||||
final var objectName = refType.equals("perm")
|
final var objectName = refType.equals("perm")
|
||||||
? idName.split(" ")[3]
|
? idName.split(" ")[3]
|
||||||
: idName.substring(refType.length()+1, idName.length()-roleType.length()-1);
|
: idName.substring(refType.length()+1, idName.length() - (roleType == null ? 0 : (roleType.length()-1)) );
|
||||||
final var tableName = objectName.split("#")[0];
|
final var tableName = objectName.contains("#") ? objectName.split("#")[0] : "";
|
||||||
final var instanceName = objectName.split("#", 2)[1];
|
final var instanceName = objectName.contains("#") ? objectName.split("#", 2)[1] : objectName;
|
||||||
final var displayName = "\n" + tableName + "\n" + instanceName + "\n" + roleType;
|
final var displayName = "\n" + tableName + "\n" + instanceName + (roleType == null ? "" : ("\n" + roleType));
|
||||||
if (refType.equals("user")) {
|
if (refType.equals("user")) {
|
||||||
return "(" + displayName + ")";
|
return "(" + displayName + ")";
|
||||||
}
|
}
|
||||||
@ -90,6 +120,6 @@ public class RbacGrantsMermaidService {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static String quoted(final String idName) {
|
private static String quoted(final String idName) {
|
||||||
return idName.replace(" ", ":");
|
return idName.replace(" ", ":").replaceAll("@.*", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import java.io.BufferedWriter;
|
|||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static java.lang.String.join;
|
import static java.lang.String.join;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@ -38,26 +39,26 @@ class RbacGrantsMermaidServiceIntegrationTest extends ContextBasedTestWithCleanu
|
|||||||
assertThat(graph).isEqualTo("""
|
assertThat(graph).isEqualTo("""
|
||||||
flowchart TB
|
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[
|
role:test_domain#xxx00-aaaa.owner[
|
||||||
test_domain
|
test_domain
|
||||||
xxx00-aaaa
|
xxx00-aaaa.o
|
||||||
owner] --> role:test_domain#xxx00-aaaa.admin[
|
owner] --> role:test_domain#xxx00-aaaa.admin[
|
||||||
test_domain
|
test_domain
|
||||||
xxx00-aaaa
|
xxx00-aaaa.a
|
||||||
admin]
|
admin]
|
||||||
role:test_domain#xxx00-aaaa.admin[
|
role:test_domain#xxx00-aaaa.admin[
|
||||||
test_domain
|
test_domain
|
||||||
xxx00-aaaa
|
xxx00-aaaa.a
|
||||||
admin] --> role:test_package#xxx00.tenant[
|
admin] --> role:test_package#xxx00.tenant[
|
||||||
test_package
|
test_package
|
||||||
xxx00
|
xxx00.t
|
||||||
tenant]
|
|
||||||
role:test_package#xxx00.tenant[
|
|
||||||
test_package
|
|
||||||
xxx00
|
|
||||||
tenant] --> role:test_customer#xxx.tenant[
|
|
||||||
test_customer
|
|
||||||
xxx
|
|
||||||
tenant]
|
tenant]
|
||||||
""".trim());
|
""".trim());
|
||||||
}
|
}
|
||||||
@ -72,53 +73,53 @@ class RbacGrantsMermaidServiceIntegrationTest extends ContextBasedTestWithCleanu
|
|||||||
|
|
||||||
role:test_domain#xxx00-aaaa.owner[
|
role:test_domain#xxx00-aaaa.owner[
|
||||||
test_domain
|
test_domain
|
||||||
xxx00-aaaa
|
xxx00-aaaa.o
|
||||||
owner] --> perm:*:on:test_domain#xxx00-aaaa{{
|
owner] --> perm:*:on:test_domain#xxx00-aaaa{{
|
||||||
test_domain
|
test_domain
|
||||||
xxx00-aaaa
|
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[
|
role:test_customer#xxx.tenant[
|
||||||
test_customer
|
test_customer
|
||||||
xxx
|
xxx.t
|
||||||
tenant] --> perm:view:on:test_customer#xxx{{
|
tenant] --> perm:view:on:test_customer#xxx{{
|
||||||
test_customer
|
test_customer
|
||||||
xxx
|
xxx
|
||||||
view}}
|
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());
|
""".trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,9 +127,13 @@ class RbacGrantsMermaidServiceIntegrationTest extends ContextBasedTestWithCleanu
|
|||||||
@Disabled
|
@Disabled
|
||||||
void print() throws IOException {
|
void print() throws IOException {
|
||||||
//context("superuser-alex@hostsharing.net", "hs_office_person#FirbySusan.admin");
|
//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"))) {
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter("doc/all-grants.md"))) {
|
||||||
writer.write("""
|
writer.write("""
|
||||||
### all grants to %s
|
### all grants to %s
|
||||||
|
Loading…
Reference in New Issue
Block a user