RBAC Diagram+PostgreSQL Generator #21
@ -19,7 +19,7 @@ public class RbacView {
|
|||||||
|
|
||||||
public static final String GLOBAL = "global";
|
public static final String GLOBAL = "global";
|
||||||
|
|
||||||
private final EntityAlias entityAlias;
|
private final EntityAlias rootEntityAlias;
|
||||||
|
|
||||||
private final Set<RbacUserReference> userDefs = new LinkedHashSet<>();
|
private final Set<RbacUserReference> userDefs = new LinkedHashSet<>();
|
||||||
private final Set<RbacRoleDefinition> roleDefs = new LinkedHashSet<>();
|
private final Set<RbacRoleDefinition> roleDefs = new LinkedHashSet<>();
|
||||||
@ -38,7 +38,7 @@ public class RbacView {
|
|||||||
private final Set<RbacGrantDefinition> grantDefs = new LinkedHashSet<>();
|
private final Set<RbacGrantDefinition> grantDefs = new LinkedHashSet<>();
|
||||||
|
|
||||||
private SQL identityViewSqlQuery;
|
private SQL identityViewSqlQuery;
|
||||||
private EntityAlias entityAliasProxy;
|
private EntityAlias rootEntityAliasProxy;
|
||||||
private RbacRoleDefinition previousRoleDef;
|
private RbacRoleDefinition previousRoleDef;
|
||||||
|
|
||||||
public static <E extends RbacObject> RbacView rbacViewFor(final String alias, final Class<E> entityClass) {
|
public static <E extends RbacObject> RbacView rbacViewFor(final String alias, final Class<E> entityClass) {
|
||||||
@ -46,8 +46,8 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RbacView(final String alias, final Class<? extends RbacObject> entityClass) {
|
RbacView(final String alias, final Class<? extends RbacObject> entityClass) {
|
||||||
entityAlias = new EntityAlias(alias, entityClass);
|
rootEntityAlias = new EntityAlias(alias, entityClass);
|
||||||
entityAliases.put(alias, entityAlias);
|
entityAliases.put(alias, rootEntityAlias);
|
||||||
new RbacUserReference(CREATOR);
|
new RbacUserReference(CREATOR);
|
||||||
entityAliases.put("global", new EntityAlias("global"));
|
entityAliases.put("global", new EntityAlias("global"));
|
||||||
}
|
}
|
||||||
@ -63,21 +63,21 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public RbacView createRole(final Role role, final Consumer<RbacRoleDefinition> with) {
|
public RbacView createRole(final Role role, final Consumer<RbacRoleDefinition> with) {
|
||||||
final RbacRoleDefinition newRoleDef = findRbacRole(entityAlias, role).toCreate();
|
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
||||||
with.accept(newRoleDef);
|
with.accept(newRoleDef);
|
||||||
previousRoleDef = newRoleDef;
|
previousRoleDef = newRoleDef;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RbacView createSubRole(final Role role) {
|
public RbacView createSubRole(final Role role) {
|
||||||
final RbacRoleDefinition newRoleDef = findRbacRole(entityAlias, role).toCreate();
|
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
||||||
findOrCreateGrantDef(newRoleDef, previousRoleDef).toCreate();
|
findOrCreateGrantDef(newRoleDef, previousRoleDef).toCreate();
|
||||||
previousRoleDef = newRoleDef;
|
previousRoleDef = newRoleDef;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RbacView createSubRole(final Role role, final Consumer<RbacRoleDefinition> with) {
|
public RbacView createSubRole(final Role role, final Consumer<RbacRoleDefinition> with) {
|
||||||
final RbacRoleDefinition newRoleDef = findRbacRole(entityAlias, role).toCreate();
|
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
||||||
findOrCreateGrantDef(newRoleDef, previousRoleDef).toCreate();
|
findOrCreateGrantDef(newRoleDef, previousRoleDef).toCreate();
|
||||||
with.accept(newRoleDef);
|
with.accept(newRoleDef);
|
||||||
previousRoleDef = newRoleDef;
|
previousRoleDef = newRoleDef;
|
||||||
@ -85,7 +85,7 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public RbacPermissionDefinition createPermission(final Permission permission) {
|
public RbacPermissionDefinition createPermission(final Permission permission) {
|
||||||
return createPermission(entityAlias, permission);
|
return createPermission(rootEntityAlias, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RbacPermissionDefinition createPermission(final EntityAlias entityAlias, final Permission permission) {
|
private RbacPermissionDefinition createPermission(final EntityAlias entityAlias, final Permission permission) {
|
||||||
@ -103,10 +103,10 @@ public class RbacView {
|
|||||||
|
|
||||||
public <EC extends RbacObject> RbacView importProxyEntity(
|
public <EC extends RbacObject> RbacView importProxyEntity(
|
||||||
final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
|
final String aliasName, final Class entityClass, final SQL fetchSql, final Column dependsOnColum) {
|
||||||
if ( entityAliasProxy != null ) {
|
if ( rootEntityAliasProxy != null ) {
|
||||||
throw new IllegalStateException("there is already an entityAliasProxy: " + entityAliasProxy);
|
throw new IllegalStateException("there is already an entityAliasProxy: " + rootEntityAliasProxy);
|
||||||
}
|
}
|
||||||
entityAliasProxy = importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum);
|
rootEntityAliasProxy = importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ public class RbacView {
|
|||||||
private RbacView importAsAlias(final String aliasName, final RbacView importedRbacView) {
|
private RbacView importAsAlias(final String aliasName, final RbacView importedRbacView) {
|
||||||
final var mapper = new AliasNameMapper(importedRbacView, aliasName);
|
final var mapper = new AliasNameMapper(importedRbacView, aliasName);
|
||||||
importedRbacView.getEntityAliases().values().stream()
|
importedRbacView.getEntityAliases().values().stream()
|
||||||
.filter(entityAlias -> !importedRbacView.isMainEntityAlias(entityAlias))
|
.filter(entityAlias -> !importedRbacView.isRootEntityAlias(entityAlias))
|
||||||
.filter(entityAlias -> !entityAlias.isGlobal())
|
.filter(entityAlias -> !entityAlias.isGlobal())
|
||||||
.forEach(entityAlias -> {
|
.forEach(entityAlias -> {
|
||||||
final String mappedAliasName = mapper.map(entityAlias.aliasName);
|
final String mappedAliasName = mapper.map(entityAlias.aliasName);
|
||||||
@ -176,12 +176,12 @@ public class RbacView {
|
|||||||
return findOrCreateGrantDef(subRoleDefinition, superRoleDefinition).toCreate();
|
return findOrCreateGrantDef(subRoleDefinition, superRoleDefinition).toCreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMainEntityAlias(final EntityAlias entityAlias) {
|
boolean isRootEntityAlias(final EntityAlias entityAlias) {
|
||||||
return entityAlias == this.entityAlias;
|
return entityAlias == this.rootEntityAlias;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEntityAliasProxy(final EntityAlias entityAlias) {
|
public boolean isEntityAliasProxy(final EntityAlias entityAlias) {
|
||||||
return entityAlias == entityAliasProxy;
|
return entityAlias == rootEntityAliasProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RbacGrantBuilder {
|
public class RbacGrantBuilder {
|
||||||
@ -545,7 +545,7 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String map(final String originalAliasName) {
|
String map(final String originalAliasName) {
|
||||||
if (originalAliasName.equals(importedRbacView.entityAlias.aliasName) ) {
|
if (originalAliasName.equals(importedRbacView.rootEntityAlias.aliasName) ) {
|
||||||
return outerAliasName;
|
return outerAliasName;
|
||||||
}
|
}
|
||||||
if (originalAliasName.equals("global") ) {
|
if (originalAliasName.equals("global") ) {
|
||||||
|
@ -36,7 +36,7 @@ public class RbacViewMermaidFlowchart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void renderEntitySubgraph(final RbacView.EntityAlias entity) {
|
private void renderEntitySubgraph(final RbacView.EntityAlias entity) {
|
||||||
final var color = rbacDef.isMainEntityAlias(entity) ? HOSTSHARING_ORANGE : HOSTSHARING_LIGHTBLUE;
|
final var color = rbacDef.isRootEntityAlias(entity) ? HOSTSHARING_ORANGE : HOSTSHARING_LIGHTBLUE;
|
||||||
flowchart.writeLn("""
|
flowchart.writeLn("""
|
||||||
|
|
||||||
subgraph %{aliasName}["`**%{aliasName}**`"]
|
subgraph %{aliasName}["`**%{aliasName}**`"]
|
||||||
@ -63,8 +63,8 @@ public class RbacViewMermaidFlowchart {
|
|||||||
.map(p -> " " + permDef(p) )
|
.map(p -> " " + permDef(p) )
|
||||||
.collect(joining("\n")));
|
.collect(joining("\n")));
|
||||||
|
|
||||||
if (rbacDef.isMainEntityAlias(entity) && rbacDef.getEntityAliasProxy() != null ) {
|
if (rbacDef.isRootEntityAlias(entity) && rbacDef.getRootEntityAliasProxy() != null ) {
|
||||||
renderEntitySubgraph(rbacDef.getEntityAliasProxy());
|
renderEntitySubgraph(rbacDef.getRootEntityAliasProxy());
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -133,7 +133,7 @@ public class RbacViewMermaidFlowchart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void generateToMarkdownFile() throws IOException {
|
void generateToMarkdownFile() throws IOException {
|
||||||
final Path path = Paths.get("doc", rbacDef.getEntityAlias().simpleName() + ".md");
|
final Path path = Paths.get("doc", rbacDef.getRootEntityAlias().simpleName() + ".md");
|
||||||
Files.writeString(
|
Files.writeString(
|
||||||
path,
|
path,
|
||||||
"""
|
"""
|
||||||
@ -143,7 +143,7 @@ public class RbacViewMermaidFlowchart {
|
|||||||
%{flowchart}
|
%{flowchart}
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
.replace("%{entityAlias}", rbacDef.getEntityAlias().aliasName())
|
.replace("%{entityAlias}", rbacDef.getRootEntityAlias().aliasName())
|
||||||
.replace("%{timestamp}", LocalDateTime.now().toString())
|
.replace("%{timestamp}", LocalDateTime.now().toString())
|
||||||
.replace("%{flowchart}", flowchart.toString()),
|
.replace("%{flowchart}", flowchart.toString()),
|
||||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
@ -18,7 +18,7 @@ public class RbacViewPostgresGenerator {
|
|||||||
|
|
||||||
public RbacViewPostgresGenerator(final RbacView forRbacDef) {
|
public RbacViewPostgresGenerator(final RbacView forRbacDef) {
|
||||||
rbacDef = forRbacDef;
|
rbacDef = forRbacDef;
|
||||||
liqibaseTagPrefix = rbacDef.getEntityAlias().entityClass().getSimpleName();
|
liqibaseTagPrefix = rbacDef.getRootEntityAlias().entityClass().getSimpleName();
|
||||||
plPgSql.append("""
|
plPgSql.append("""
|
||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- generated at: %{timestamp}
|
-- generated at: %{timestamp}
|
||||||
|
@ -29,7 +29,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
this.rbacGrants.addAll(rbacGrants);
|
this.rbacGrants.addAll(rbacGrants);
|
||||||
this.liquibaseTagPrefix = liquibaseTagPrefix;
|
this.liquibaseTagPrefix = liquibaseTagPrefix;
|
||||||
|
|
||||||
entityClass = rbacDef.getEntityAlias().entityClass();
|
entityClass = rbacDef.getRootEntityAlias().entityClass();
|
||||||
simpleEntityName = entityClass.getSimpleName();
|
simpleEntityName = entityClass.getSimpleName();
|
||||||
simpleEntityVarName = uncapitalize(simpleEntityName);
|
simpleEntityVarName = uncapitalize(simpleEntityName);
|
||||||
rawTableName = withoutRvSuffix(entityClass.getAnnotation(Table.class).name());
|
rawTableName = withoutRvSuffix(entityClass.getAnnotation(Table.class).name());
|
||||||
@ -89,7 +89,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
private void createRolesWithGrantsSql(final StringBuilder plPgSql, final RbacView.Role role) {
|
private void createRolesWithGrantsSql(final StringBuilder plPgSql, final RbacView.Role role) {
|
||||||
|
|
||||||
final var isToCreate = rbacDef.getRoleDefs().stream()
|
final var isToCreate = rbacDef.getRoleDefs().stream()
|
||||||
.filter(roleDef -> rbacDef.isMainEntityAlias(roleDef.getEntityAlias()) && roleDef.getRole() == role )
|
.filter(roleDef -> rbacDef.isRootEntityAlias(roleDef.getEntityAlias()) && roleDef.getRole() == role )
|
||||||
.findFirst().map(RbacView.RbacRoleDefinition::isToCreate).orElse(false);
|
.findFirst().map(RbacView.RbacRoleDefinition::isToCreate).orElse(false);
|
||||||
if (!isToCreate) {
|
if (!isToCreate) {
|
||||||
return;
|
return;
|
||||||
@ -103,7 +103,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
.replace("%{simpleEntityVarName)", simpleEntityVarName)
|
.replace("%{simpleEntityVarName)", simpleEntityVarName)
|
||||||
.replace("%{roleSuffix}", capitalize(role.roleName())));
|
.replace("%{roleSuffix}", capitalize(role.roleName())));
|
||||||
|
|
||||||
final var permissionGrantsForRole = findPermissionsGrantsForRole(rbacDef.getEntityAlias(), role);
|
final var permissionGrantsForRole = findPermissionsGrantsForRole(rbacDef.getRootEntityAlias(), role);
|
||||||
if (!permissionGrantsForRole.isEmpty()) {
|
if (!permissionGrantsForRole.isEmpty()) {
|
||||||
final var permissionsForRoleInPlPgSql = permissionGrantsForRole.stream()
|
final var permissionsForRoleInPlPgSql = permissionGrantsForRole.stream()
|
||||||
.map(RbacView.RbacGrantDefinition::getPermDef)
|
.map(RbacView.RbacGrantDefinition::getPermDef)
|
||||||
@ -115,7 +115,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
rbacGrants.removeAll(permissionGrantsForRole);
|
rbacGrants.removeAll(permissionGrantsForRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
final var grantsToUsers = findGrantsToUserForRole(rbacDef.getEntityAlias(), role);
|
final var grantsToUsers = findGrantsToUserForRole(rbacDef.getRootEntityAlias(), role);
|
||||||
if (!grantsToUsers.isEmpty()) {
|
if (!grantsToUsers.isEmpty()) {
|
||||||
final var grantsToUsersPlPgSql = grantsToUsers.stream()
|
final var grantsToUsersPlPgSql = grantsToUsers.stream()
|
||||||
.map(RbacView.RbacGrantDefinition::getUserDef)
|
.map(RbacView.RbacGrantDefinition::getUserDef)
|
||||||
@ -125,7 +125,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
rbacGrants.removeAll(grantsToUsers);
|
rbacGrants.removeAll(grantsToUsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
final var incomingGrants = findIncomingSuperRolesForRole(rbacDef.getEntityAlias(), role);
|
final var incomingGrants = findIncomingSuperRolesForRole(rbacDef.getRootEntityAlias(), role);
|
||||||
if (!incomingGrants.isEmpty()) {
|
if (!incomingGrants.isEmpty()) {
|
||||||
final var incomingGrantsInPlPgSql = incomingGrants.stream()
|
final var incomingGrantsInPlPgSql = incomingGrants.stream()
|
||||||
.map(RbacView.RbacGrantDefinition::getSuperRoleDef)
|
.map(RbacView.RbacGrantDefinition::getSuperRoleDef)
|
||||||
@ -135,7 +135,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
rbacGrants.removeAll(incomingGrants);
|
rbacGrants.removeAll(incomingGrants);
|
||||||
}
|
}
|
||||||
|
|
||||||
final var outgoingGrants = findOutgoingSuperRolesForRole(rbacDef.getEntityAlias(), role);
|
final var outgoingGrants = findOutgoingSuperRolesForRole(rbacDef.getRootEntityAlias(), role);
|
||||||
if (!outgoingGrants.isEmpty()) {
|
if (!outgoingGrants.isEmpty()) {
|
||||||
final var outgoingGrantsInPlPgSql = outgoingGrants.stream()
|
final var outgoingGrantsInPlPgSql = outgoingGrants.stream()
|
||||||
.map(RbacView.RbacGrantDefinition::getSuperRoleDef)
|
.map(RbacView.RbacGrantDefinition::getSuperRoleDef)
|
||||||
@ -218,7 +218,7 @@ class RolesGrantsAndPermissionsGenerator {
|
|||||||
private String toPlPgSqlReference(final PostgresTriggerReference triggerRef, final RbacView.RbacRoleDefinition roleDef) {
|
private String toPlPgSqlReference(final PostgresTriggerReference triggerRef, final RbacView.RbacRoleDefinition roleDef) {
|
||||||
return toVar(roleDef) +
|
return toVar(roleDef) +
|
||||||
(roleDef.getEntityAlias().isGlobal() ? "()"
|
(roleDef.getEntityAlias().isGlobal() ? "()"
|
||||||
: rbacDef.isMainEntityAlias(roleDef.getEntityAlias()) ? ("(" + triggerRef.name() + ")")
|
: rbacDef.isRootEntityAlias(roleDef.getEntityAlias()) ? ("(" + triggerRef.name() + ")")
|
||||||
: "(" + toTriggerReference(triggerRef, roleDef.getEntityAlias()) + ")");
|
: "(" + toTriggerReference(triggerRef, roleDef.getEntityAlias()) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user