diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetEntity.java index ae181921..efd768e0 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetEntity.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.UUID; import static java.util.Collections.emptyMap; +import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.CaseDef.inCaseOf; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.ColumnValue.usingDefaultCase; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL; @@ -51,6 +52,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.UPDATE; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT; +import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.GUEST; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.OWNER; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.REFERRER; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT; @@ -199,6 +201,13 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti directlyFetchedByDependsOnColumn(), NULLABLE) + .switchOnColumn("type", + inCaseOf("DOMAIN_SETUP", then -> { + then.toRole(GLOBAL, GUEST).grantPermission(INSERT); + then.toRole(GLOBAL, ADMIN).grantPermission(SELECT); // FIXME: remove + }) + ) + .createRole(OWNER, (with) -> { with.incomingSuperRole("bookingItem", ADMIN); with.incomingSuperRole("parentAsset", ADMIN); @@ -217,8 +226,11 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti with.outgoingSubRole("bookingItem", TENANT); with.outgoingSubRole("parentAsset", TENANT); with.incomingSuperRole("alarmContact", ADMIN); + with.incomingSuperRole(GLOBAL, GUEST); // FIXME: remove + with.incomingSuperRole(GLOBAL, ADMIN); // FIXME: remove with.permission(SELECT); }) + .limitDiagramTo("asset", "bookingItem", "bookingItem.debitorRel", "parentAsset", "assignedToAsset", "alarmContact", "global"); } diff --git a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7013-hs-hosting-asset-rbac.md b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7013-hs-hosting-asset-rbac.md index f0b250db..5dbee08b 100644 --- a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7013-hs-hosting-asset-rbac.md +++ b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7013-hs-hosting-asset-rbac.md @@ -36,9 +36,9 @@ subgraph asset["`**asset**`"] style asset:permissions fill:#dd4901,stroke:white perm:asset:INSERT{{asset:INSERT}} + perm:asset:SELECT{{asset:SELECT}} perm:asset:DELETE{{asset:DELETE}} perm:asset:UPDATE{{asset:UPDATE}} - perm:asset:SELECT{{asset:SELECT}} end end @@ -99,10 +99,14 @@ role:asset:AGENT ==> role:asset:TENANT role:asset:TENANT ==> role:bookingItem:TENANT role:asset:TENANT ==> role:parentAsset:TENANT role:alarmContact:ADMIN ==> role:asset:TENANT +role:global:GUEST ==> role:asset:TENANT +role:global:ADMIN ==> role:asset:TENANT %% granting permissions to roles role:global:ADMIN ==> perm:asset:INSERT role:parentAsset:ADMIN ==> perm:asset:INSERT +role:global:GUEST ==> perm:asset:INSERT +role:global:ADMIN ==> perm:asset:SELECT role:asset:OWNER ==> perm:asset:DELETE role:asset:ADMIN ==> perm:asset:UPDATE role:asset:TENANT ==> perm:asset:SELECT 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 cbaffa47..9c5cb70d 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 @@ -75,6 +75,8 @@ begin hsHostingAssetTENANT(NEW), permissions => array['SELECT'], incomingSuperRoles => array[ + globalADMIN(), + globalGUEST(), hsHostingAssetAGENT(NEW), hsOfficeContactADMIN(newAlarmContact)], outgoingSubRoles => array[ @@ -82,6 +84,13 @@ begin hsHostingAssetTENANT(newParentAsset)] ); + IF NEW.type = 'DOMAIN_SETUP' THEN + END IF; + + + + call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), globalAdmin()); + call leaveTriggerForObjectUuid(NEW.uuid); end; $$; @@ -147,114 +156,6 @@ execute procedure updateTriggerForHsHostingAsset_tf(); --// --- ============================================================================ ---changeset hs-hosting-asset-rbac-GRANTING-INSERT-PERMISSION:1 endDelimiter:--// --- ---------------------------------------------------------------------------- - --- granting INSERT permission to global ---------------------------- - -/* - Grants INSERT INTO hs_hosting_asset permissions to specified role of pre-existing global rows. - */ -do language plpgsql $$ - declare - row global; - begin - call defineContext('create INSERT INTO hs_hosting_asset permissions for pre-exising global rows'); - - FOR row IN SELECT * FROM global - -- unconditional for all rows in that table - LOOP - call grantPermissionToRole( - createPermission(row.uuid, 'INSERT', 'hs_hosting_asset'), - globalADMIN()); - END LOOP; - end; -$$; - -/** - Grants hs_hosting_asset INSERT permission to specified role of new global rows. -*/ -create or replace function new_hs_hosting_asset_grants_insert_to_global_tf() - returns trigger - language plpgsql - strict as $$ -begin - -- unconditional for all rows in that table - call grantPermissionToRole( - createPermission(NEW.uuid, 'INSERT', 'hs_hosting_asset'), - globalADMIN()); - -- end. - return NEW; -end; $$; - --- z_... is to put it at the end of after insert triggers, to make sure the roles exist -create trigger z_new_hs_hosting_asset_grants_insert_to_global_tg - after insert on global - for each row -execute procedure new_hs_hosting_asset_grants_insert_to_global_tf(); - --- granting INSERT permission to hs_hosting_asset ---------------------------- - --- 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. -*/ -create or replace function new_hs_hosting_asset_grants_insert_to_hs_hosting_asset_tf() - returns trigger - language plpgsql - strict as $$ -begin - -- unconditional for all rows in that table - call grantPermissionToRole( - createPermission(NEW.uuid, 'INSERT', 'hs_hosting_asset'), - hsHostingAssetADMIN(NEW)); - -- end. - return NEW; -end; $$; - --- z_... is to put it at the end of after insert triggers, to make sure the roles exist -create trigger z_new_hs_hosting_asset_grants_insert_to_hs_hosting_asset_tg - after insert on hs_hosting_asset - for each row -execute procedure new_hs_hosting_asset_grants_insert_to_hs_hosting_asset_tf(); - - --- ============================================================================ ---changeset hs_hosting_asset-rbac-CHECKING-INSERT-PERMISSION:1 endDelimiter:--// --- ---------------------------------------------------------------------------- - -/** - Checks if the user respectively the assumed roles are allowed to insert a row to hs_hosting_asset. -*/ -create or replace function hs_hosting_asset_insert_permission_check_tf() - returns trigger - language plpgsql as $$ -declare - superObjectUuid uuid; -begin - -- check INSERT INSERT if global ADMIN - if isGlobalAdmin() then - return NEW; - end if; - -- check INSERT permission via direct foreign key: NEW.parentAssetUuid - if hasInsertPermission(NEW.parentAssetUuid, 'hs_hosting_asset') then - return NEW; - end if; - - raise exception '[403] insert into hs_hosting_asset values(%) not allowed for current subjects % (%)', - NEW, currentSubjects(), currentSubjectsUuids(); -end; $$; - -create trigger hs_hosting_asset_insert_permission_check_tg - before insert on hs_hosting_asset - for each row - execute procedure hs_hosting_asset_insert_permission_check_tf(); ---// - - -- ============================================================================ --changeset hs-hosting-asset-rbac-IDENTITY-VIEW:1 endDelimiter:--// -- ---------------------------------------------------------------------------- diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java index cc8a029b..100d5e95 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java @@ -27,6 +27,7 @@ import java.util.Map; import static java.util.Map.entry; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE; import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf; @@ -153,12 +154,39 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu null)); } + @Test + public void anyUser_canCreateNewDomainSetupAsset() { + // given + context("superuser-alex@hostsharing.net"); + final var assetCount = assetRepo.count(); + + // when + context("person-SmithPeter@example.com"); + final var result = attempt(em, () -> { + final var newAsset = HsHostingAssetEntity.builder() + .caption("some new domain setup") + .type(DOMAIN_SETUP) + .identifier("example.org") + .build(); + return toCleanup(assetRepo.save(newAsset)); + }); + + // then + result.assertSuccessful(); + assertThat(result.returnedValue()).isNotNull().extracting(HsHostingAssetEntity::getUuid).isNotNull(); + assertThat(result.returnedValue().isLoaded()).isFalse(); + context("superuser-alex@hostsharing.net"); + assertThatAssetIsPersisted(result.returnedValue()); + assertThat(assetRepo.count()).isEqualTo(assetCount + 1); + } + private void assertThatAssetIsPersisted(final HsHostingAssetEntity saved) { + final var context = attempt(em, () -> { - context("superuser-alex@hostsharing.net"); final var found = assetRepo.findByUuid(saved.getUuid()); assertThat(found).isNotEmpty().map(HsHostingAssetEntity::toString).get().isEqualTo(saved.toString()); }); + } }