From 4dafa031a0ffabe2d90aa36dabbf929dc7824bbc Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 25 Apr 2024 14:03:35 +0200 Subject: [PATCH] fixex for generated multiple insert permission grants to hs_hosting_asset --- .../rbac/rbacdef/InsertTriggerGenerator.java | 98 ++++++++++++------- .../hsadminng/rbac/rbacdef/RbacView.java | 26 ++--- .../7013-hs-hosting-asset-rbac.sql | 11 +-- 3 files changed, 78 insertions(+), 57 deletions(-) diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/InsertTriggerGenerator.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/InsertTriggerGenerator.java index 79dee390..03e1516f 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/InsertTriggerGenerator.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/InsertTriggerGenerator.java @@ -1,9 +1,11 @@ package net.hostsharing.hsadminng.rbac.rbacdef; import java.util.Optional; +import java.util.Set; import java.util.function.BinaryOperator; import java.util.stream.Stream; +import static java.util.stream.Collectors.joining; import static net.hostsharing.hsadminng.rbac.rbacdef.PostgresTriggerReference.NEW; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.PERM_TO_ROLE; @@ -25,7 +27,6 @@ public class InsertTriggerGenerator { void generateTo(final StringWriter plPgSql) { generateInsertGrants(plPgSql); generateInsertPermissionChecks(plPgSql); - plPgSql.writeLn("--//"); } private void generateInsertGrants(final StringWriter plPgSql) { @@ -53,35 +54,45 @@ public class InsertTriggerGenerator { plPgSql.writeLn(""" -- granting INSERT permission to ${rawSubTable} ---------------------------- """, - with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName())); + with("rawSubTable", g.getSuperRoleDef().getEntityAlias().getRawTableName())); - plPgSql.writeLn(""" - /* - Grants INSERT INTO ${rawSubTable} permissions to specified role of pre-existing ${rawSuperTable} rows. - */ - do language plpgsql $$ - declare - preExistingRow ${rawSuperTable}; - begin - call defineContext('create INSERT INTO ${rawSubTable} permissions for pre-exising ${rawSuperTable} rows'); - - FOR preExistingRow IN SELECT * FROM ${rawSuperTable} - ${whenCondition} - LOOP - call grantPermissionToRole( - createPermission(preExistingRow.uuid, 'INSERT', '${rawSubTable}'), - hsBookingItemAGENT(preExistingRow)); - END LOOP; - end; - $$; - """, - with("whenCondition", g.getSuperRoleDef().getEntityAlias().isCaseDependent() - // TODO.impl: .type needs to be dynamically generated - ? "WHERE preExistingRow.type = '${value}'" + if (isGrantToADifferentTable(g)) { + plPgSql.writeLn( + """ + /* + Grants INSERT INTO ${rawSubTable} permissions to specified role of pre-existing ${rawSuperTable} rows. + */ + do language plpgsql $$ + declare + preExistingRow ${rawSuperTable}; + begin + call defineContext('create INSERT INTO ${rawSubTable} permissions for pre-exising ${rawSuperTable} rows'); + + FOR preExistingRow IN SELECT * FROM ${rawSuperTable} + ${whenCondition} + LOOP + call grantPermissionToRole( + createPermission(preExistingRow.uuid, 'INSERT', '${rawSubTable}'), + hsBookingItemAGENT(preExistingRow)); + END LOOP; + end; + $$; + """, + with("whenCondition", g.getSuperRoleDef().getEntityAlias().isCaseDependent() + // TODO.impl: .type needs to be dynamically generated + ? "WHERE preExistingRow.type = '${value}'" .replace("${value}", g.getSuperRoleDef().getEntityAlias().usingCase().value) - : "-- unconditional for all rows in that table"), - with("rawSuperTable", g.getSuperRoleDef().getEntityAlias().getRawTableName()), - with("rawSubTable", g.getPermDef().getEntityAlias().getRawTableName())); + : "-- unconditional for all rows in that table"), + with("rawSuperTable", g.getSuperRoleDef().getEntityAlias().getRawTableName()), + with("rawSubTable", g.getPermDef().getEntityAlias().getRawTableName())); + } else { + plPgSql.writeLn(""" + -- Granting INSERT INTO hs_hosting_asset permissions to specified role of pre-existing hs_hosting_asset rows slipped, + -- because there cannot yet be any pre-existing rows in the same table yet. + """, + with("rawSuperTable", g.getSuperRoleDef().getEntityAlias().getRawTableName()), + with("rawSubTable", g.getPermDef().getEntityAlias().getRawTableName())); + } plPgSql.writeLn(""" /** @@ -150,7 +161,6 @@ public class InsertTriggerGenerator { plPgSql.writeLn("--//"); } - private void generateInsertPermissionChecks(final StringWriter plPgSql) { plPgSql.writeLn(""" -- ============================================================================ @@ -177,20 +187,30 @@ public class InsertTriggerGenerator { when ( not ( """, with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName())); + plPgSql.chopEmptyLines(); - plPgSql.indented(2, () -> { + plPgSql.indented(3, () -> { getInsertGrants().forEach(g -> { final RbacView.EntityAlias superRoleEntityAlias = g.getSuperRoleDef().getEntityAlias(); + final RbacView.EntityAlias permissionEntityAlias = g.getPermDef().entityAlias; final var caseCondition = superRoleEntityAlias.isCaseDependent() - ? "NEW.type = '" + superRoleEntityAlias.usingCase().value + "' and " + ? ("NEW.type in (" + toStringList(g.getForCases()) + ") and ") : ""; - plPgSql.writeLn("${caseCondition}hasInsertPermission(NEW.${refColumn}, 'INSERT', '${rawSubTable}') or", - with("caseCondition", caseCondition), - with("refColumn", superRoleEntityAlias.dependsOnColumName()), - with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName())); + if ( g.getSuperRoleDef().isGlobalAdmin() ) { + plPgSql.writeLn( + "${caseCondition}isGlobalAdmin() or", + with("caseCondition", caseCondition)); + } else { + plPgSql.writeLn( + "${caseCondition}hasInsertPermission(NEW.${refColumn}, '${rawSubTable}') or", + with("caseCondition", caseCondition), + with("refColumn", superRoleEntityAlias.dependsOnColumName()), + with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName())); + } }); plPgSql.chopTail(" or\n"); }); + plPgSql.writeLn(); plPgSql.writeLn(""" ) ) @@ -200,6 +220,14 @@ public class InsertTriggerGenerator { with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName())); } + private String toStringList(final Set cases) { + return cases.stream().map(c -> "'" + c.value + "'").collect(joining(", ")); + } + + private boolean isGrantToADifferentTable(final RbacView.RbacGrantDefinition g) { + return !rbacDef.getRootEntityAlias().getRawTableName().equals(g.getSuperRoleDef().getEntityAlias().getRawTableName()); + } + private Stream getInsertGrants() { return rbacDef.getGrantDefs().stream() .filter(g -> g.grantType() == PERM_TO_ROLE) diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java index b9b556a9..718ee146 100644 --- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java +++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacdef/RbacView.java @@ -560,11 +560,13 @@ public class RbacView { register(this); } - public RbacGrantDefinition(final RbacPermissionDefinition permDef, final RbacRoleDefinition roleDef) { + public RbacGrantDefinition(final RbacPermissionDefinition permDef, final RbacRoleDefinition roleDef, + final CaseDef forCase) { this.userDef = null; this.subRoleDef = null; this.superRoleDef = roleDef; this.permDef = permDef; + this.forCases = forCase != null ? hashSet(forCase) : null; register(this); } @@ -676,7 +678,8 @@ public class RbacView { final String tableName; final boolean toCreate; - private RbacPermissionDefinition(final EntityAlias entityAlias, final Permission permission, final String tableName, final boolean toCreate) { + private RbacPermissionDefinition(final EntityAlias entityAlias, final Permission permission, final String tableName, + final boolean toCreate) { this.entityAlias = entityAlias; this.permission = permission; this.tableName = tableName; @@ -788,6 +791,10 @@ public class RbacView { public String toString() { return "role:" + entityAlias.aliasName + role; } + + public boolean isGlobalAdmin() { + return entityAlias.isGlobal() && role == Role.ADMIN; + } } public RbacUserReference findUserRef(final RbacUserReference.UserRole userRole) { @@ -842,19 +849,6 @@ public class RbacView { .orElseGet(() -> new RbacPermissionDefinition(entityAlias, perm, tableName, true)); // TODO: true => toCreate } - - RbacPermissionDefinition findRbacPerm(final EntityAlias entityAlias, final Permission perm) { - return findRbacPerm(entityAlias, perm, null); - } - - public RbacPermissionDefinition findRbacPerm(final String entityAliasName, final Permission perm, String tableName) { - return findRbacPerm(findEntityAlias(entityAliasName), perm, tableName); - } - - public RbacPermissionDefinition findRbacPerm(final String entityAliasName, final Permission perm) { - return findRbacPerm(findEntityAlias(entityAliasName), perm); - } - private RbacGrantDefinition findOrCreateGrantDef(final RbacRoleDefinition roleDefinition, final RbacUserReference user) { return grantDefs.stream() .filter(g -> g.subRoleDef == roleDefinition && g.userDef == user) @@ -866,7 +860,7 @@ public class RbacView { return grantDefs.stream() .filter(g -> g.permDef == permDef && g.superRoleDef == roleDef) .findFirst() - .orElseGet(() -> new RbacGrantDefinition(permDef, roleDef)); + .orElseGet(() -> new RbacGrantDefinition(permDef, roleDef, processingCase)); } private RbacGrantDefinition findOrCreateGrantDef( diff --git a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7013-hs-hosting-asset-rbac.sql b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7013-hs-hosting-asset-rbac.sql index 4db57b5d..2f19be08 100644 --- a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7013-hs-hosting-asset-rbac.sql +++ b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7013-hs-hosting-asset-rbac.sql @@ -138,10 +138,8 @@ execute procedure new_hs_hosting_asset_grants_insert_to_hs_booking_item_tf(); -- granting INSERT permission to hs_hosting_asset ---------------------------- -/* - Grants INSERT INTO hs_hosting_asset permissions to specified role of pre-existing hs_hosting_asset rows. - */ --- Skipped, because there cannot yet be any pre-existing hs_hosting_asset rows. +-- Granting INSERT INTO hs_hosting_asset permissions to specified role of pre-existing hs_hosting_asset rows slipped, +-- because there cannot yet be any pre-existing rows in the same table yet. /** Grants hs_hosting_asset INSERT permission to specified role of new hs_hosting_asset rows. @@ -189,11 +187,12 @@ create trigger hs_hosting_asset_insert_permission_check_tg for each row when ( not ( hasInsertPermission(NEW.bookingItemUuid, 'hs_hosting_asset') or - NEW.type = 'MANAGED_WEBSPACE' and hasInsertPermission(NEW.parentAssetUuid, 'INSERT', 'hs_hosting_asset') ) ) + NEW.type in ('MANAGED_WEBSPACE') and hasInsertPermission(NEW.parentAssetUuid, 'hs_hosting_asset') + ) ) execute procedure hs_hosting_asset_insert_permission_missing_tf(); - --// + -- ============================================================================ --changeset hs-hosting-asset-rbac-IDENTITY-VIEW:1 endDelimiter:--// -- ----------------------------------------------------------------------------