RBAC Diagram+PostgreSQL Generator #21
@ -105,17 +105,19 @@ public class HsOfficeSepaMandateEntity implements Stringifyable, HasUuid {
|
||||
.createRole(OWNER, (with) -> {
|
||||
with.owningUser(CREATOR);
|
||||
with.incomingSuperRole(GLOBAL, ADMIN);
|
||||
with.outgoingSubRole("bankAccount", REFERRER);
|
||||
with.permission(ALL);
|
||||
})
|
||||
.createSubRole(ADMIN, (with) -> {
|
||||
with.permission(EDIT);
|
||||
})
|
||||
.createSubRole(AGENT, (with) -> {
|
||||
with.outgoingSubRole("bankAccount", REFERRER);
|
||||
with.outgoingSubRole("debitorRel", AGENT);
|
||||
})
|
||||
.createSubRole(REFERRER, (with) -> {
|
||||
with.incomingSuperRole("bankAccount", ADMIN);
|
||||
with.incomingSuperRole("debitorRel", AGENT);
|
||||
with.outgoingSubRole("debitorRel", TENANT);
|
||||
with.permission(VIEW);
|
||||
});
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import jakarta.validation.constraints.NotNull;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.autoFetched;
|
||||
import static org.apache.commons.lang3.StringUtils.uncapitalize;
|
||||
@ -300,6 +301,18 @@ public class RbacView {
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean dependsOnColumn(final String columnName) {
|
||||
return dependsRoleDefOnColumnName(this.superRoleDef, columnName)
|
||||
|| dependsRoleDefOnColumnName(this.subRoleDef, columnName);
|
||||
}
|
||||
|
||||
private Boolean dependsRoleDefOnColumnName(final RbacRoleDefinition superRoleDef, final String columnName) {
|
||||
return ofNullable(superRoleDef)
|
||||
.map(r -> r.getEntityAlias().dependsOnColum())
|
||||
.map(d -> columnName.equals(d.column))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
public enum GrantType {
|
||||
ROLE_TO_USER,
|
||||
ROLE_TO_ROLE,
|
||||
|
@ -4,10 +4,12 @@ import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacPermissionDefinition;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.PostgresTriggerReference.NEW;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.PostgresTriggerReference.OLD;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.getRawTableName;
|
||||
@ -79,12 +81,19 @@ class RolesGrantsAndPermissionsGenerator {
|
||||
});
|
||||
});
|
||||
|
||||
plPgSql.writeLn("""
|
||||
begin
|
||||
if TG_OP <> 'INSERT' then
|
||||
raise exception 'invalid usage of TRIGGER AFTER INSERT function';
|
||||
end if;
|
||||
""");
|
||||
plPgSql.indented(() -> {
|
||||
plPgSql.writeLn("begin");
|
||||
generateCreateRolesAndGrantsAfterInsert(plPgSql);
|
||||
generateUpdateRolesAndGrantsAfterUpdate(plPgSql);
|
||||
plPgSql.ensureEmptyLine();
|
||||
plPgSql.writeLn("end; $$;");
|
||||
});
|
||||
plPgSql.writeLn();
|
||||
}
|
||||
|
||||
private void generateCreateRolesAndGrantsAfterInsert(final StringWriter plPgSql) {
|
||||
plPgSql.ensureEmptyLine();
|
||||
plPgSql.writeLn("if TG_OP = 'INSERT' then");
|
||||
|
||||
plPgSql.indented(() -> {
|
||||
|
||||
@ -106,8 +115,53 @@ class RolesGrantsAndPermissionsGenerator {
|
||||
generateGrants(plPgSql, PERM_TO_ROLE);
|
||||
});
|
||||
|
||||
plPgSql.writeLn("end; $$;");
|
||||
plPgSql.writeLn();
|
||||
plPgSql.writeLn("end if;");
|
||||
}
|
||||
|
||||
private void generateUpdateRolesAndGrantsAfterUpdate(final StringWriter plPgSql) {
|
||||
plPgSql.ensureEmptyLine();
|
||||
plPgSql.writeLn("if TG_OP = 'UPDATE' then");
|
||||
|
||||
plPgSql.indented(() -> {
|
||||
|
||||
rbacDef.getEntityAliases().values().stream()
|
||||
.filter(ea -> !rbacDef.isRootEntityAlias(ea))
|
||||
.filter(ea -> ea.fetchSql() != null)
|
||||
.forEach(ea -> {
|
||||
plPgSql.writeLn( ea.fetchSql().sql.replace("${ref}", OLD.name()) + " into " + entityRefVar(OLD, ea) + ";");
|
||||
});
|
||||
|
||||
rbacDef.getEntityAliases().values().stream()
|
||||
.map(RbacView.EntityAlias::dependsOnColum)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(this::isUpdatable)
|
||||
.map(c -> c.column)
|
||||
.sorted()
|
||||
.distinct()
|
||||
.forEach(columnName -> {
|
||||
plPgSql.writeLn();
|
||||
plPgSql.writeLn("if NEW." + columnName + " <> OLD." + columnName + " then");
|
||||
plPgSql.indented(() -> {
|
||||
updateGrantsDependingOn(plPgSql, columnName);
|
||||
});
|
||||
plPgSql.writeLn("end if;");
|
||||
});
|
||||
});
|
||||
|
||||
plPgSql.writeLn("end if;");
|
||||
}
|
||||
|
||||
private boolean isUpdatable(final RbacView.Column c) {
|
||||
return rbacDef.getUpdatableColumns().contains(c);
|
||||
}
|
||||
|
||||
private void updateGrantsDependingOn(final StringWriter plPgSql, final String columnName) {
|
||||
rbacDef.getGrantDefs().stream()
|
||||
.filter(RbacView.RbacGrantDefinition::isToCreate)
|
||||
.filter(g -> g.dependsOnColumn(columnName))
|
||||
.forEach(g -> {
|
||||
plPgSql.writeLn("-- TODO: " + g);
|
||||
});
|
||||
}
|
||||
|
||||
private void generateGrants(final StringWriter plPgSql, final RbacView.RbacGrantDefinition.GrantType grantType) {
|
||||
|
Loading…
Reference in New Issue
Block a user