implement insert trigger if no explicit grant rule is specified

This commit is contained in:
Michael Hoennig 2024-03-07 12:26:07 +01:00
parent 20de9ba7a4
commit b37e8044b2
6 changed files with 81 additions and 23 deletions

View File

@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.rbac.rbacdef; package net.hostsharing.hsadminng.rbac.rbacdef;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.PERM_TO_ROLE; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.PERM_TO_ROLE;
@ -95,10 +96,6 @@ public class InsertTriggerGenerator {
} }
private void generateInsertCheckTrigger(final StringWriter plPgSql) { private void generateInsertCheckTrigger(final StringWriter plPgSql) {
rbacDef.getGrantDefs().stream()
.filter(g -> g.isToCreate() && g.grantType() == PERM_TO_ROLE &&
g.getPermDef().getPermission() == INSERT )
.forEach(g -> {
plPgSql.writeLn(""" plPgSql.writeLn("""
/** /**
Checks if the user or assumed roles are allowed to insert a row to ${rawSubTable}. Checks if the user or assumed roles are allowed to insert a row to ${rawSubTable}.
@ -107,24 +104,51 @@ public class InsertTriggerGenerator {
returns trigger returns trigger
language plpgsql as $$ language plpgsql as $$
begin begin
raise exception 'insert into ${rawSubTable} not allowed for current subjects %', currentSubjectsUuids(); raise exception 'insert into ${rawSubTable} not allowed for current subjects % (%)',
currentSubjects(), currentSubjectsUuids();
end; $$; end; $$;
""",
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()));
getOptionalInsertGrant().ifPresentOrElse(g -> {
plPgSql.writeLn("""
create trigger ${rawSubTable}_insert_permission_check_tg create trigger ${rawSubTable}_insert_permission_check_tg
before insert on ${rawSubTable} before insert on ${rawSubTable}
for each row for each row
when ( not hasInsertPermission(NEW.${referenceColumn}, 'INSERT', '${rawSubTable}') ) when ( not hasInsertPermission(NEW.${referenceColumn}, 'INSERT', '${rawSubTable}') )
execute procedure ${rawSubTable}_insert_permission_missing_tf(); execute procedure ${rawSubTable}_insert_permission_missing_tf();
""", """,
with("rawSubTable", g.getPermDef().entityAlias.getRawTableName()), with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()),
with("referenceColumn", g.getSuperRoleDef().getEntityAlias().dependsOnColumName() )); with("referenceColumn", g.getSuperRoleDef().getEntityAlias().dependsOnColumName() ));
},
() -> {
plPgSql.writeLn("""
create trigger ${rawSubTable}_insert_permission_check_tg
before insert on ${rawSubTable}
for each row
-- As there is no explicit INSERT grant specified for this table,
-- only global admins are allowed to insert any rows.
when ( not isGlobalAdmin() )
execute procedure ${rawSubTable}_insert_permission_missing_tf();
""",
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()));
});
}
private Stream<RbacView.RbacGrantDefinition> getInsertGrants() {
return rbacDef.getGrantDefs().stream()
.filter(g -> g.grantType() == PERM_TO_ROLE)
.filter(g -> g.getPermDef().toCreate && g.getPermDef().getPermission() == INSERT);
}
private Optional<RbacView.RbacGrantDefinition> getOptionalInsertGrant() {
return getInsertGrants()
.reduce((x, y) -> {
throw new IllegalStateException("only a single INSERT permission grant allowed");
}); });
} }
private Optional<RbacView.RbacRoleDefinition> getOptionalInsertSuperRole() { private Optional<RbacView.RbacRoleDefinition> getOptionalInsertSuperRole() {
return rbacDef.getGrantDefs().stream() return getInsertGrants()
.filter(g -> g.grantType() == PERM_TO_ROLE)
.filter(g -> g.getPermDef().toCreate && g.getPermDef().getPermission() == INSERT)
.map(RbacView.RbacGrantDefinition::getSuperRoleDef) .map(RbacView.RbacGrantDefinition::getSuperRoleDef)
.reduce((x, y) -> { .reduce((x, y) -> {
throw new IllegalStateException("only a single INSERT permission grant allowed"); throw new IllegalStateException("only a single INSERT permission grant allowed");

View File

@ -334,6 +334,7 @@ class RolesGrantsAndPermissionsGenerator {
.map(RbacPermissionDefinition::getPermission) .map(RbacPermissionDefinition::getPermission)
.map(RbacView.Permission::permission) .map(RbacView.Permission::permission)
.map(p -> "'" + p + "'") .map(p -> "'" + p + "'")
.sorted()
.toList(); .toList();
plPgSql.indented(() -> plPgSql.indented(() ->
plPgSql.writeLn("permissions => array[" + joinArrayElements(arrayElements, 3) + "],\n")); plPgSql.writeLn("permissions => array[" + joinArrayElements(arrayElements, 3) + "],\n"));

View File

@ -22,6 +22,19 @@ grant select on global to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
--// --//
-- ============================================================================
--changeset rbac-global-IS-GLOBAL-ADMIN:1 endDelimiter:--//
-- ------------------------------------------------------------------
create or replace function isGlobalAdmin()
returns boolean
language plpgsql as $$
begin
return isGranted(currentSubjectsUuids(), findRoleId(globalAdmin()));
end; $$;
--//
-- ============================================================================ -- ============================================================================
--changeset rbac-global-HAS-GLOBAL-PERMISSION:1 endDelimiter:--// --changeset rbac-global-HAS-GLOBAL-PERMISSION:1 endDelimiter:--//
-- ------------------------------------------------------------------ -- ------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-06T15:40:13.239729250. -- This code generated was by RbacViewPostgresGenerator at 2024-03-07T12:25:36.376742633.
-- ============================================================================ -- ============================================================================
@ -80,6 +80,25 @@ execute procedure insertTriggerForTestCustomer_tf();
--changeset test-customer-rbac-INSERT:1 endDelimiter:--// --changeset test-customer-rbac-INSERT:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
/**
Checks if the user or assumed roles are allowed to insert a row to test_customer.
*/
create or replace function test_customer_insert_permission_missing_tf()
returns trigger
language plpgsql as $$
begin
raise exception 'insert into test_customer not allowed for current subjects % (%)',
currentSubjects(), currentSubjectsUuids();
end; $$;
create trigger test_customer_insert_permission_check_tg
before insert on test_customer
for each row
-- As there is no explicit INSERT grant specified for this table,
-- only global admins are allowed to insert any rows.
when ( not isGlobalAdmin() )
execute procedure test_customer_insert_permission_missing_tf();
--// --//
-- ============================================================================ -- ============================================================================

View File

@ -1,5 +1,5 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-06T15:40:13.277446553. -- This code generated was by RbacViewPostgresGenerator at 2024-03-07T12:25:36.422351715.
-- ============================================================================ -- ============================================================================
@ -194,7 +194,8 @@ create or replace function test_package_insert_permission_missing_tf()
returns trigger returns trigger
language plpgsql as $$ language plpgsql as $$
begin begin
raise exception 'insert into test_package not allowed for current subjects %', currentSubjectsUuids(); raise exception 'insert into test_package not allowed for current subjects % (%)',
currentSubjects(), currentSubjectsUuids();
end; $$; end; $$;
create trigger test_package_insert_permission_check_tg create trigger test_package_insert_permission_check_tg

View File

@ -74,7 +74,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then // then
result.assertExceptionWithRootCauseMessage( result.assertExceptionWithRootCauseMessage(
PersistenceException.class, PersistenceException.class,
"add-customer not permitted for test_customer#xxx.admin"); "ERROR: insert into test_customer not allowed for current subjects {test_customer#xxx.admin}");
} }
@Test @Test
@ -92,7 +92,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then // then
result.assertExceptionWithRootCauseMessage( result.assertExceptionWithRootCauseMessage(
PersistenceException.class, PersistenceException.class,
"add-customer not permitted for customer-admin@xxx.example.com"); "ERROR: insert into test_customer not allowed for current subjects {customer-admin@xxx.example.com}");
} }