fix indrirect permission by indirect foreign key

This commit is contained in:
Michael Hoennig 2024-03-25 05:57:58 +01:00
parent 823269d8aa
commit fd7630aaa8
3 changed files with 74 additions and 18 deletions

View File

@ -114,7 +114,16 @@ public class InsertTriggerGenerator {
}
}
} else {
generateInsertPermissionTriggerAllowByRoleOfDirectForeignKey(plPgSql, g);
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 {
generateInsertPermissionTriggerAllowByRoleOfDirectForeignKey(plPgSql, g);
}
}
},
() -> {
@ -149,6 +158,50 @@ public class InsertTriggerGenerator {
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) {
plPgSql.writeLn("""
/**

View File

@ -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.
*/
@ -1052,21 +1069,6 @@ public class RbacView {
HsOfficeSepaMandateEntity.class,
HsOfficeCoopSharesTransactionEntity.class,
HsOfficeMembershipEntity.class
).forEach(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");
}
});
).forEach(RbacView::generateRbacView);
}
}

View File

@ -4,8 +4,9 @@ spring:
platform: postgres
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: ${spring.datasource.url-tc}
username: postgres
password: password