improved RBAC generators #26
@ -113,8 +113,17 @@ public class InsertTriggerGenerator {
|
|||||||
"invalid global role for INSERT permission: " + g.getSuperRoleDef().getRole());
|
"invalid global role for INSERT permission: " + g.getSuperRoleDef().getRole());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
final var superRoleEntityAlias = g.getSuperRoleDef().getEntityAlias();
|
||||||
|
|
||||||
|
// TODO: Maybe this should depend on the indirection degree of the fetchSql?
|
||||||
|
// Maybe we need a separate fetchedBy method for all the simple, direct cases?
|
||||||
|
if (superRoleEntityAlias.fetchSql().sql.contains("JOIN ")) {
|
||||||
|
generateInsertPermissionTriggerAllowByRoleOfIndirectForeignKey(plPgSql, g);
|
||||||
} else {
|
} else {
|
||||||
generateInsertPermissionTriggerAllowByRoleOfDirectForeignKey(plPgSql, g);
|
generateInsertPermissionTriggerAllowByRoleOfDirectForeignKey(plPgSql, g);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() -> {
|
() -> {
|
||||||
@ -149,6 +158,50 @@ public class InsertTriggerGenerator {
|
|||||||
with("referenceColumn", g.getSuperRoleDef().getEntityAlias().dependsOnColumName()));
|
with("referenceColumn", g.getSuperRoleDef().getEntityAlias().dependsOnColumName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateInsertPermissionTriggerAllowByRoleOfIndirectForeignKey(
|
||||||
|
final StringWriter plPgSql,
|
||||||
|
final RbacView.RbacGrantDefinition g) {
|
||||||
|
plPgSql.writeLn("""
|
||||||
|
/**
|
||||||
|
Checks if the user or assumed roles are allowed to insert a row to ${rawSubTable},
|
||||||
|
where the check is performed by an indirect role.
|
||||||
|
|
||||||
|
An indirect role is a role FIXME.
|
||||||
|
*/
|
||||||
|
create or replace function ${rawSubTable}_insert_permission_missing_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql as $$
|
||||||
|
begin
|
||||||
|
if ( not hasInsertPermission(
|
||||||
|
( SELECT ${varName}.uuid FROM
|
||||||
|
""",
|
||||||
|
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()),
|
||||||
|
with("varName", g.getSuperRoleDef().getEntityAlias().aliasName()));
|
||||||
|
plPgSql.indented(3, () -> {
|
||||||
|
plPgSql.writeLn(
|
||||||
|
"(" + g.getSuperRoleDef().getEntityAlias().fetchSql().sql + ") AS ${varName}",
|
||||||
|
with("varName", g.getSuperRoleDef().getEntityAlias().aliasName()),
|
||||||
|
with("ref", NEW.name()));
|
||||||
|
});
|
||||||
|
plPgSql.writeLn("""
|
||||||
|
|
||||||
|
), 'INSERT', '${rawSubTable}') ) then
|
||||||
|
raise exception
|
||||||
|
'[403] insert into ${rawSubTable} not allowed for current subjects % (%)',
|
||||||
|
currentSubjects(), currentSubjectsUuids();
|
||||||
|
end if;
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger ${rawSubTable}_insert_permission_check_tg
|
||||||
|
before insert on ${rawSubTable}
|
||||||
|
for each row
|
||||||
|
execute procedure ${rawSubTable}_insert_permission_missing_tf();
|
||||||
|
|
||||||
|
""",
|
||||||
|
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()));
|
||||||
|
}
|
||||||
|
|
||||||
private void generateInsertPermissionTriggerAllowOnlyGlobalAdmin(final StringWriter plPgSql) {
|
private void generateInsertPermissionTriggerAllowOnlyGlobalAdmin(final StringWriter plPgSql) {
|
||||||
plPgSql.writeLn("""
|
plPgSql.writeLn("""
|
||||||
/**
|
/**
|
||||||
|
@ -1033,6 +1033,23 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void generateRbacView(final Class<? extends HasUuid> c) {
|
||||||
|
final Method mainMethod = stream(c.getMethods()).filter(
|
||||||
|
m -> isStatic(m.getModifiers()) && m.getName().equals("main")
|
||||||
|
)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (mainMethod != null) {
|
||||||
|
try {
|
||||||
|
mainMethod.invoke(null, new Object[] { null });
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("WARNING: no main method in: " + c.getName() + " => no RBAC rules generated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This main method generates the RbacViews (PostgreSQL+diagram) for all given entity classes.
|
* This main method generates the RbacViews (PostgreSQL+diagram) for all given entity classes.
|
||||||
*/
|
*/
|
||||||
@ -1052,21 +1069,6 @@ public class RbacView {
|
|||||||
HsOfficeSepaMandateEntity.class,
|
HsOfficeSepaMandateEntity.class,
|
||||||
HsOfficeCoopSharesTransactionEntity.class,
|
HsOfficeCoopSharesTransactionEntity.class,
|
||||||
HsOfficeMembershipEntity.class
|
HsOfficeMembershipEntity.class
|
||||||
).forEach(c -> {
|
).forEach(RbacView::generateRbacView);
|
||||||
final Method mainMethod = stream(c.getMethods()).filter(
|
|
||||||
m -> isStatic(m.getModifiers()) && m.getName().equals("main")
|
|
||||||
)
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
if (mainMethod != null) {
|
|
||||||
try {
|
|
||||||
mainMethod.invoke(null, new Object[] { null });
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.err.println("WARNING: no main method in: " + c.getName() + " => no RBAC rules generated");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,9 @@ spring:
|
|||||||
platform: postgres
|
platform: postgres
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers
|
url-tc: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers
|
||||||
url-local: jdbc:postgresql://localhost:5432/postgres
|
url-local: jdbc:postgresql://localhost:5432/postgres
|
||||||
|
url: ${spring.datasource.url-tc}
|
||||||
username: postgres
|
username: postgres
|
||||||
password: password
|
password: password
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user