From 81e6ddab9119727b542dd6cc16f84575194d177a Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Sat, 1 Jun 2024 10:47:26 +0200 Subject: [PATCH] fixing rbac --- .../hs/booking/item/HsBookingItemEntity.java | 37 +++-- .../project/HsBookingProjectEntity.java | 5 +- .../asset/HsHostingAssetController.java | 16 +-- .../hosting/asset/HsHostingAssetEntity.java | 38 ++--- .../6103-hs-booking-project-rbac.md | 67 +++++---- .../6103-hs-booking-project-rbac.sql | 8 +- .../620-booking-item/6200-hs-booking-item.sql | 8 +- .../6203-hs-booking-item-rbac.md | 4 +- .../6203-hs-booking-item-rbac.sql | 105 ++++++++++++-- .../6208-hs-booking-item-test-data.sql | 16 ++- .../7010-hs-hosting-asset.sql | 2 +- .../7013-hs-hosting-asset-rbac.md | 21 +-- .../7013-hs-hosting-asset-rbac.sql | 130 +++++++++--------- ...HsBookingItemControllerAcceptanceTest.java | 76 +++++----- ...sBookingItemRepositoryIntegrationTest.java | 51 +++---- ...okingProjectRepositoryIntegrationTest.java | 1 - ...sHostingAssetControllerAcceptanceTest.java | 25 ++-- ...HostingAssetRepositoryIntegrationTest.java | 26 ++-- 18 files changed, 372 insertions(+), 264 deletions(-) diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntity.java index b1da2f06..00ce3d5e 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntity.java @@ -42,7 +42,7 @@ import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateR import static net.hostsharing.hsadminng.mapper.PostgresDateRange.upperInclusiveFromPostgresDateRange; 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.Nullable.NOT_NULL; +import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NULLABLE; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.DELETE; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT; @@ -79,10 +79,14 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject, Validatab @Version private int version; - @ManyToOne(optional = false) + @ManyToOne @JoinColumn(name = "projectuuid") private HsBookingProjectEntity project; + @ManyToOne + @JoinColumn(name = "parentitemuuid") + private HsBookingItemEntity parentItem; + @Column(name = "type") @Enumerated(EnumType.STRING) private HsBookingItemType type; @@ -135,10 +139,17 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject, Validatab @Override public String toShortString() { - return ofNullable(project).map(HsBookingProjectEntity::toShortString).orElse("D-???????-?") + + return ofNullable(relatedProject()).map(HsBookingProjectEntity::toShortString).orElse("D-???????-?") + ":" + caption; } + private HsBookingProjectEntity relatedProject() { + if (project != null) { + return project; + } + return parentItem == null ? null : parentItem.relatedProject(); + } + @Override public String getPropertiesName() { return "resources"; @@ -151,31 +162,35 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject, Validatab public static RbacView rbac() { return rbacViewFor("bookingItem", HsBookingItemEntity.class) - .withIdentityView(SQL.query(""" - SELECT bookingItem.uuid as uuid, projectIV.idName || '-' || cleanIdentifier(bookingItem.caption) as idName - FROM hs_booking_item bookingItem - JOIN hs_booking_project_iv projectIV ON projectIV.uuid = bookingItem.projectUuid - """)) + .withIdentityView(SQL.projection("caption")) // FIXME: cleanIdentifier(...)? .withRestrictedViewOrderBy(SQL.expression("validity")) .withUpdatableColumns("version", "caption", "validity", "resources") + .toRole("global", ADMIN).grantPermission(INSERT) // FIXME: Why is this necessary to insert test data? + .toRole("global", ADMIN).grantPermission(DELETE) .importEntityAlias("project", HsBookingProjectEntity.class, usingDefaultCase(), dependsOnColumn("projectUuid"), directlyFetchedByDependsOnColumn(), - NOT_NULL) + NULLABLE) .toRole("project", ADMIN).grantPermission(INSERT) - .toRole("global", ADMIN).grantPermission(DELETE) + + .importEntityAlias("parentItem", HsBookingItemEntity.class, usingDefaultCase(), + dependsOnColumn("parentItemUuid"), + directlyFetchedByDependsOnColumn(), + NULLABLE) + .toRole("parentItem", ADMIN).grantPermission(INSERT) .createRole(OWNER, (with) -> { with.incomingSuperRole("project", AGENT); + with.incomingSuperRole("parentItem", AGENT); }) .createSubRole(ADMIN, (with) -> { - with.incomingSuperRole("project", AGENT); with.permission(UPDATE); }) .createSubRole(AGENT) .createSubRole(TENANT, (with) -> { with.outgoingSubRole("project", TENANT); + with.outgoingSubRole("parentItem", TENANT); with.permission(SELECT); }) diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/project/HsBookingProjectEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/project/HsBookingProjectEntity.java index 75fa9209..aee3242f 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/project/HsBookingProjectEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/project/HsBookingProjectEntity.java @@ -66,7 +66,7 @@ public class HsBookingProjectEntity implements Stringifyable, RbacObject { } public static RbacView rbac() { - return rbacViewFor("bookingProject", HsBookingProjectEntity.class) + return rbacViewFor("project", HsBookingProjectEntity.class) .withIdentityView(SQL.query(""" SELECT bookingProject.uuid as uuid, debitorIV.idName || '-' || cleanIdentifier(bookingProject.caption) as idName FROM hs_booking_project bookingProject @@ -96,7 +96,6 @@ public class HsBookingProjectEntity implements Stringifyable, RbacObject { with.incomingSuperRole("debitorRel", AGENT); }) .createSubRole(ADMIN, (with) -> { - with.incomingSuperRole("debitorRel", AGENT); with.permission(UPDATE); }) .createSubRole(AGENT) @@ -105,7 +104,7 @@ public class HsBookingProjectEntity implements Stringifyable, RbacObject { with.permission(SELECT); }) - .limitDiagramTo("bookingProject", "debitorRel", "global"); + .limitDiagramTo("project", "debitorRel", "global"); } public static void main(String[] args) throws IOException { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetController.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetController.java index 57e91ec5..a645bb78 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetController.java @@ -78,14 +78,14 @@ public class HsHostingAssetController implements HsHostingAssetsApi { public ResponseEntity getAssetByUuid( final String currentUser, final String assumedRoles, - final UUID serverUuid) { + final UUID assetUuid) { context.define(currentUser, assumedRoles); - final var result = assetRepo.findByUuid(serverUuid); + final var result = assetRepo.findByUuid(assetUuid); return result - .map(serverEntity -> ResponseEntity.ok( - mapper.map(serverEntity, HsHostingAssetResource.class))) + .map(assetEntity -> ResponseEntity.ok( + mapper.map(assetEntity, HsHostingAssetResource.class))) .orElseGet(() -> ResponseEntity.notFound().build()); } @@ -94,10 +94,10 @@ public class HsHostingAssetController implements HsHostingAssetsApi { public ResponseEntity deleteAssetUuid( final String currentUser, final String assumedRoles, - final UUID serverUuid) { + final UUID assetUuid) { context.define(currentUser, assumedRoles); - final var result = assetRepo.deleteByUuid(serverUuid); + final var result = assetRepo.deleteByUuid(assetUuid); return result == 0 ? ResponseEntity.notFound().build() : ResponseEntity.noContent().build(); @@ -108,12 +108,12 @@ public class HsHostingAssetController implements HsHostingAssetsApi { public ResponseEntity patchAsset( final String currentUser, final String assumedRoles, - final UUID serverUuid, + final UUID assetUuid, final HsHostingAssetPatchResource body) { context.define(currentUser, assumedRoles); - final var current = assetRepo.findByUuid(serverUuid).orElseThrow(); + final var current = assetRepo.findByUuid(assetUuid).orElseThrow(); new HsHostingAssetEntityPatcher(current).apply(body); 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 8cd628e6..03ef92e0 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 @@ -33,11 +33,7 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; -import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER; 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.rbacdef.RbacView.CaseDef.inCaseOf; -import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.CaseDef.inOtherCases; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.ColumnValue.usingCase; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.ColumnValue.usingDefaultCase; @@ -80,11 +76,11 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Validata @Version private int version; - @ManyToOne(optional = false) + @ManyToOne @JoinColumn(name = "bookingitemuuid") private HsBookingItemEntity bookingItem; - @ManyToOne(optional = true) + @ManyToOne @JoinColumn(name = "parentassetuuid") private HsHostingAssetEntity parentAsset; @@ -140,42 +136,36 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Validata .withIdentityView(SQL.projection("identifier")) .withRestrictedViewOrderBy(SQL.expression("identifier")) .withUpdatableColumns("version", "caption", "config") + .toRole(GLOBAL, ADMIN).grantPermission(INSERT) // FIXME: Why is this necessary to insert test data? .importEntityAlias("bookingItem", HsBookingItemEntity.class, usingDefaultCase(), dependsOnColumn("bookingItemUuid"), directlyFetchedByDependsOnColumn(), NULLABLE) + .toRole("bookingItem", AGENT).grantPermission(INSERT) - .switchOnColumn("type", - inCaseOf(CLOUD_SERVER.name(), - then -> then.toRole("bookingItem", AGENT).grantPermission(INSERT)), - inCaseOf(MANAGED_SERVER.name(), - then -> then.toRole("bookingItem", AGENT).grantPermission(INSERT)), - inCaseOf(MANAGED_WEBSPACE.name(), then -> - then.importEntityAlias("parentServer", HsHostingAssetEntity.class, usingCase(MANAGED_SERVER), - dependsOnColumn("parentAssetUuid"), - directlyFetchedByDependsOnColumn(), - NULLABLE) - .toRole("parentServer", ADMIN).grantPermission(INSERT) - .toRole("bookingItem", AGENT).grantPermission(INSERT) - ), - inOtherCases(then -> {}) - ) + .importEntityAlias("parentAsset", HsHostingAssetEntity.class, usingCase(MANAGED_SERVER), + dependsOnColumn("parentAssetUuid"), + directlyFetchedByDependsOnColumn(), + NULLABLE) + .toRole("parentAsset", ADMIN).grantPermission(INSERT) .createRole(OWNER, (with) -> { with.incomingSuperRole("bookingItem", ADMIN); + with.incomingSuperRole("parentAsset", ADMIN); with.permission(DELETE); }) .createSubRole(ADMIN, (with) -> { + with.incomingSuperRole("bookingItem", AGENT); + with.incomingSuperRole("parentAsset", AGENT); with.permission(UPDATE); }) + .createSubRole(AGENT) .createSubRole(TENANT, (with) -> { with.outgoingSubRole("bookingItem", TENANT); + with.outgoingSubRole("parentAsset", TENANT); with.permission(SELECT); }) - - .toRole(GLOBAL, ADMIN).grantPermission(INSERT) - .limitDiagramTo("asset", "bookingItem", "bookingItem.debitorRel", "parentServer", "global"); } diff --git a/src/main/resources/db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.md b/src/main/resources/db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.md index d082cc80..270908a8 100644 --- a/src/main/resources/db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.md +++ b/src/main/resources/db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.md @@ -1,4 +1,4 @@ -### rbac bookingProject +### rbac project This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. @@ -6,29 +6,6 @@ This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manua %%{init:{'flowchart':{'htmlLabels':false}}}%% flowchart TB -subgraph bookingProject["`**bookingProject**`"] - direction TB - style bookingProject fill:#dd4901,stroke:#274d6e,stroke-width:8px - - subgraph bookingProject:roles[ ] - style bookingProject:roles fill:#dd4901,stroke:white - - role:bookingProject:OWNER[[bookingProject:OWNER]] - role:bookingProject:ADMIN[[bookingProject:ADMIN]] - role:bookingProject:AGENT[[bookingProject:AGENT]] - role:bookingProject:TENANT[[bookingProject:TENANT]] - end - - subgraph bookingProject:permissions[ ] - style bookingProject:permissions fill:#dd4901,stroke:white - - perm:bookingProject:INSERT{{bookingProject:INSERT}} - perm:bookingProject:DELETE{{bookingProject:DELETE}} - perm:bookingProject:UPDATE{{bookingProject:UPDATE}} - perm:bookingProject:SELECT{{bookingProject:SELECT}} - end -end - subgraph debitorRel["`**debitorRel**`"] direction TB style debitorRel fill:#99bcdb,stroke:#274d6e,stroke-width:8px @@ -43,22 +20,44 @@ subgraph debitorRel["`**debitorRel**`"] end end +subgraph project["`**project**`"] + direction TB + style project fill:#dd4901,stroke:#274d6e,stroke-width:8px + + subgraph project:roles[ ] + style project:roles fill:#dd4901,stroke:white + + role:project:OWNER[[project:OWNER]] + role:project:ADMIN[[project:ADMIN]] + role:project:AGENT[[project:AGENT]] + role:project:TENANT[[project:TENANT]] + end + + subgraph project:permissions[ ] + style project:permissions fill:#dd4901,stroke:white + + perm:project:INSERT{{project:INSERT}} + perm:project:DELETE{{project:DELETE}} + perm:project:UPDATE{{project:UPDATE}} + perm:project:SELECT{{project:SELECT}} + end +end + %% granting roles to roles role:global:ADMIN -.-> role:debitorRel:OWNER role:debitorRel:OWNER -.-> role:debitorRel:ADMIN role:debitorRel:ADMIN -.-> role:debitorRel:AGENT role:debitorRel:AGENT -.-> role:debitorRel:TENANT -role:debitorRel:AGENT ==> role:bookingProject:OWNER -role:bookingProject:OWNER ==> role:bookingProject:ADMIN -role:debitorRel:AGENT ==> role:bookingProject:ADMIN -role:bookingProject:ADMIN ==> role:bookingProject:AGENT -role:bookingProject:AGENT ==> role:bookingProject:TENANT -role:bookingProject:TENANT ==> role:debitorRel:TENANT +role:debitorRel:AGENT ==> role:project:OWNER +role:project:OWNER ==> role:project:ADMIN +role:project:ADMIN ==> role:project:AGENT +role:project:AGENT ==> role:project:TENANT +role:project:TENANT ==> role:debitorRel:TENANT %% granting permissions to roles -role:debitorRel:ADMIN ==> perm:bookingProject:INSERT -role:global:ADMIN ==> perm:bookingProject:DELETE -role:bookingProject:ADMIN ==> perm:bookingProject:UPDATE -role:bookingProject:TENANT ==> perm:bookingProject:SELECT +role:debitorRel:ADMIN ==> perm:project:INSERT +role:global:ADMIN ==> perm:project:DELETE +role:project:ADMIN ==> perm:project:UPDATE +role:project:TENANT ==> perm:project:SELECT ``` diff --git a/src/main/resources/db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.sql b/src/main/resources/db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.sql index 7f4e173e..e0e0a9b7 100644 --- a/src/main/resources/db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.sql +++ b/src/main/resources/db/changelog/6-hs-booking/610-booking-project/6103-hs-booking-project-rbac.sql @@ -55,9 +55,7 @@ begin perform createRoleWithGrants( hsBookingProjectADMIN(NEW), permissions => array['UPDATE'], - incomingSuperRoles => array[ - hsBookingProjectOWNER(NEW), - hsOfficeRelationAGENT(newDebitorRel)] + incomingSuperRoles => array[hsBookingProjectOWNER(NEW)] ); perform createRoleWithGrants( @@ -169,8 +167,8 @@ begin return NEW; end if; - raise exception '[403] insert into hs_booking_project not allowed for current subjects % (%)', - currentSubjects(), currentSubjectsUuids(); + raise exception '[403] insert into hs_booking_project values(%) not allowed for current subjects % (%)', + NEW, currentSubjects(), currentSubjectsUuids(); end; $$; create trigger hs_booking_project_insert_permission_check_tg diff --git a/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6200-hs-booking-item.sql b/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6200-hs-booking-item.sql index 096b2600..077bc33a 100644 --- a/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6200-hs-booking-item.sql +++ b/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6200-hs-booking-item.sql @@ -17,11 +17,15 @@ create table if not exists hs_booking_item ( uuid uuid unique references RbacObject (uuid), version int not null default 0, - projectUuid uuid not null references hs_booking_project(uuid), + projectUuid uuid null references hs_booking_project(uuid), type HsBookingItemType not null, + parentItemUuid uuid null references hs_booking_item(uuid) initially deferred, validity daterange not null, caption varchar(80) not null, - resources jsonb not null + resources jsonb not null, + + constraint chk_hs_booking_item_has_project_or_parent_asset + check (type in ('CLOUD_SERVER', 'MANAGED_SERVER') or projectUuid is not null or parentItemUuid is not null) ); --// diff --git a/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.md b/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.md index 067241e4..4775616f 100644 --- a/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.md +++ b/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.md @@ -49,14 +49,14 @@ role:project:ADMIN -.-> role:project:AGENT role:project:AGENT -.-> role:project:TENANT role:project:AGENT ==> role:bookingItem:OWNER role:bookingItem:OWNER ==> role:bookingItem:ADMIN -role:project:AGENT ==> role:bookingItem:ADMIN role:bookingItem:ADMIN ==> role:bookingItem:AGENT role:bookingItem:AGENT ==> role:bookingItem:TENANT role:bookingItem:TENANT ==> role:project:TENANT %% granting permissions to roles -role:project:ADMIN ==> perm:bookingItem:INSERT +role:global:ADMIN ==> perm:bookingItem:INSERT role:global:ADMIN ==> perm:bookingItem:DELETE +role:project:ADMIN ==> perm:bookingItem:INSERT role:bookingItem:ADMIN ==> perm:bookingItem:UPDATE role:bookingItem:TENANT ==> perm:bookingItem:SELECT diff --git a/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.sql b/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.sql index e0475e6b..bcd6523e 100644 --- a/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.sql +++ b/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6203-hs-booking-item-rbac.sql @@ -31,25 +31,26 @@ create or replace procedure buildRbacSystemForHsBookingItem( declare newProject hs_booking_project; + newParentItem hs_booking_item; begin call enterTriggerForObjectUuid(NEW.uuid); SELECT * FROM hs_booking_project WHERE uuid = NEW.projectUuid INTO newProject; - assert newProject.uuid is not null, format('newProject must not be null for NEW.projectUuid = %s', NEW.projectUuid); + SELECT * FROM hs_booking_item WHERE uuid = NEW.parentItemUuid INTO newParentItem; perform createRoleWithGrants( hsBookingItemOWNER(NEW), - incomingSuperRoles => array[hsBookingProjectAGENT(newProject)] + incomingSuperRoles => array[ + hsBookingItemAGENT(newParentItem), + hsBookingProjectAGENT(newProject)] ); perform createRoleWithGrants( hsBookingItemADMIN(NEW), permissions => array['UPDATE'], - incomingSuperRoles => array[ - hsBookingItemOWNER(NEW), - hsBookingProjectAGENT(newProject)] + incomingSuperRoles => array[hsBookingItemOWNER(NEW)] ); perform createRoleWithGrants( @@ -61,9 +62,13 @@ begin hsBookingItemTENANT(NEW), permissions => array['SELECT'], incomingSuperRoles => array[hsBookingItemAGENT(NEW)], - outgoingSubRoles => array[hsBookingProjectTENANT(newProject)] + outgoingSubRoles => array[ + hsBookingItemTENANT(newParentItem), + hsBookingProjectTENANT(newProject)] ); + + call grantPermissionToRole(createPermission(NEW.uuid, 'DELETE'), globalAdmin()); call leaveTriggerForObjectUuid(NEW.uuid); @@ -93,6 +98,49 @@ execute procedure insertTriggerForHsBookingItem_tf(); --changeset hs-booking-item-rbac-GRANTING-INSERT-PERMISSION:1 endDelimiter:--// -- ---------------------------------------------------------------------------- +-- granting INSERT permission to global ---------------------------- + +/* + Grants INSERT INTO hs_booking_item permissions to specified role of pre-existing global rows. + */ +do language plpgsql $$ + declare + row global; + begin + call defineContext('create INSERT INTO hs_booking_item 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_booking_item'), + globalADMIN()); + END LOOP; + end; +$$; + +/** + Grants hs_booking_item INSERT permission to specified role of new global rows. +*/ +create or replace function new_hs_booking_item_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_booking_item'), + 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_booking_item_grants_insert_to_global_tg + after insert on global + for each row +execute procedure new_hs_booking_item_grants_insert_to_global_tf(); + -- granting INSERT permission to hs_booking_project ---------------------------- /* @@ -136,6 +184,33 @@ create trigger z_new_hs_booking_item_grants_insert_to_hs_booking_project_tg for each row execute procedure new_hs_booking_item_grants_insert_to_hs_booking_project_tf(); +-- granting INSERT permission to hs_booking_item ---------------------------- + +-- 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_booking_item INSERT permission to specified role of new hs_booking_item rows. +*/ +create or replace function new_hs_booking_item_grants_insert_to_hs_booking_item_tf() + returns trigger + language plpgsql + strict as $$ +begin + -- unconditional for all rows in that table + call grantPermissionToRole( + createPermission(NEW.uuid, 'INSERT', 'hs_booking_item'), + hsBookingItemADMIN(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_booking_item_grants_insert_to_hs_booking_item_tg + after insert on hs_booking_item + for each row +execute procedure new_hs_booking_item_grants_insert_to_hs_booking_item_tf(); + -- ============================================================================ --changeset hs_booking_item-rbac-CHECKING-INSERT-PERMISSION:1 endDelimiter:--// @@ -150,13 +225,21 @@ create or replace function hs_booking_item_insert_permission_check_tf() 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.projectUuid if hasInsertPermission(NEW.projectUuid, 'hs_booking_item') then return NEW; end if; + -- check INSERT permission via direct foreign key: NEW.parentItemUuid + if hasInsertPermission(NEW.parentItemUuid, 'hs_booking_item') then + return NEW; + end if; - raise exception '[403] insert into hs_booking_item not allowed for current subjects % (%)', - currentSubjects(), currentSubjectsUuids(); + raise exception '[403] insert into hs_booking_item values(%) not allowed for current subjects % (%)', + NEW, currentSubjects(), currentSubjectsUuids(); end; $$; create trigger hs_booking_item_insert_permission_check_tg @@ -170,11 +253,9 @@ create trigger hs_booking_item_insert_permission_check_tg --changeset hs-booking-item-rbac-IDENTITY-VIEW:1 endDelimiter:--// -- ---------------------------------------------------------------------------- -call generateRbacIdentityViewFromQuery('hs_booking_item', +call generateRbacIdentityViewFromProjection('hs_booking_item', $idName$ - SELECT bookingItem.uuid as uuid, projectIV.idName || '-' || cleanIdentifier(bookingItem.caption) as idName - FROM hs_booking_item bookingItem - JOIN hs_booking_project_iv projectIV ON projectIV.uuid = bookingItem.projectUuid + caption $idName$); --// diff --git a/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6208-hs-booking-item-test-data.sql b/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6208-hs-booking-item-test-data.sql index 91aca115..bc3a9e51 100644 --- a/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6208-hs-booking-item-test-data.sql +++ b/src/main/resources/db/changelog/6-hs-booking/620-booking-item/6208-hs-booking-item-test-data.sql @@ -16,6 +16,8 @@ create or replace procedure createHsBookingItemTransactionTestData( declare currentTask varchar; relatedProject hs_booking_project; + privateCloudUuid uuid; + managedServerUuid uuid; begin currentTask := 'creating booking-item test-data ' || givenPartnerNumber::text || givenDebitorSuffix; call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global:ADMIN'); @@ -27,11 +29,17 @@ begin raise notice 'creating test booking-item: %', givenPartnerNumber::text || givenDebitorSuffix::text; raise notice '- using project (%): %', relatedProject.uuid, relatedProject; + privateCloudUuid := uuid_generate_v4(); + managedServerUuid := uuid_generate_v4(); insert - into hs_booking_item (uuid, projectuuid, type, caption, validity, resources) - values (uuid_generate_v4(), relatedProject.uuid, 'MANAGED_SERVER', 'some ManagedServer', daterange('20221001', null, '[]'), '{ "CPUs": 2, "RAM": 8, "SDD": 512, "Traffic": 42 }'::jsonb), - (uuid_generate_v4(), relatedProject.uuid, 'CLOUD_SERVER', 'some CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "HDD": 1024, "Traffic": 42 }'::jsonb), - (uuid_generate_v4(), relatedProject.uuid, 'PRIVATE_CLOUD', 'some PrivateCloud', daterange('20240401', null, '[]'), '{ "CPUs": 10, "SDD": 10240, "HDD": 10240, "Traffic": 42 }'::jsonb); + into hs_booking_item (uuid, projectuuid, type, parentitemuuid, caption, validity, resources) + values (privateCloudUuid, relatedProject.uuid, 'PRIVATE_CLOUD', null, 'some PrivateCloud', daterange('20240401', null, '[]'), '{ "CPUs": 10, "SDD": 10240, "HDD": 10240, "Traffic": 42 }'::jsonb), + (uuid_generate_v4(), null, 'MANAGED_SERVER', privateCloudUuid, 'some ManagedServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "HDD": 1024, "Traffic": 42 }'::jsonb), + (uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'test CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "HDD": 1024, "Traffic": 42 }'::jsonb), + (uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'prod CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 4, "RAM": 16, "HDD": 2924, "Traffic": 420 }'::jsonb), + (managedServerUuid, relatedProject.uuid, 'MANAGED_SERVER', null, 'separate ManagedServer', daterange('20221001', null, '[]'), '{ "CPUs": 2, "RAM": 8, "SDD": 512, "Traffic": 42 }'::jsonb), + (uuid_generate_v4(), null, 'MANAGED_WEBSPACE', managedServerUuid, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SDD": 512, "Traffic": 12, "Daemons": 2, "Multi": 4 }'::jsonb), + (uuid_generate_v4(), relatedProject.uuid, 'MANAGED_WEBSPACE', null, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SDD": 512, "Traffic": 12, "Daemons": 2, "Multi": 4 }'::jsonb); end; $$; --// diff --git a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql index 6609bbe8..43bacc43 100644 --- a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql +++ b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql @@ -26,7 +26,7 @@ create table if not exists hs_hosting_asset version int not null default 0, bookingItemUuid uuid null references hs_booking_item(uuid), type HsHostingAssetType not null, - parentAssetUuid uuid null references hs_hosting_asset(uuid), + parentAssetUuid uuid null references hs_hosting_asset(uuid) initially deferred, identifier varchar(80) not null, caption varchar(80), config jsonb not null, 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 66472b8a..b9a65745 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 @@ -1,4 +1,4 @@ -### rbac asset inOtherCases +### rbac asset This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually. @@ -15,6 +15,7 @@ subgraph asset["`**asset**`"] role:asset:OWNER[[asset:OWNER]] role:asset:ADMIN[[asset:ADMIN]] + role:asset:AGENT[[asset:AGENT]] role:asset:TENANT[[asset:TENANT]] end @@ -42,30 +43,22 @@ subgraph bookingItem["`**bookingItem**`"] end end -subgraph parentServer["`**parentServer**`"] - direction TB - style parentServer fill:#99bcdb,stroke:#274d6e,stroke-width:8px - - subgraph parentServer:roles[ ] - style parentServer:roles fill:#99bcdb,stroke:white - - role:parentServer:ADMIN[[parentServer:ADMIN]] - end -end - %% granting roles to roles role:bookingItem:OWNER -.-> role:bookingItem:ADMIN role:bookingItem:ADMIN -.-> role:bookingItem:AGENT role:bookingItem:AGENT -.-> role:bookingItem:TENANT role:bookingItem:ADMIN ==> role:asset:OWNER role:asset:OWNER ==> role:asset:ADMIN -role:asset:ADMIN ==> role:asset:TENANT +role:bookingItem:AGENT ==> role:asset:ADMIN +role:asset:ADMIN ==> role:asset:AGENT +role:asset:AGENT ==> role:asset:TENANT role:asset:TENANT ==> role:bookingItem:TENANT %% granting permissions to roles +role:global:ADMIN ==> perm:asset:INSERT +role:bookingItem:AGENT ==> perm:asset:INSERT role:asset:OWNER ==> perm:asset:DELETE role:asset:ADMIN ==> perm:asset:UPDATE role:asset:TENANT ==> perm:asset:SELECT -role:global:ADMIN ==> perm:asset:INSERT ``` 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 ae6fe27a..ae6c51c7 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 @@ -30,41 +30,47 @@ create or replace procedure buildRbacSystemForHsHostingAsset( language plpgsql as $$ declare - newParentServer hs_hosting_asset; newBookingItem hs_booking_item; + newParentAsset hs_hosting_asset; begin call enterTriggerForObjectUuid(NEW.uuid); - SELECT * FROM hs_hosting_asset WHERE uuid = NEW.parentAssetUuid INTO newParentServer; - SELECT * FROM hs_booking_item WHERE uuid = NEW.bookingItemUuid INTO newBookingItem; + SELECT * FROM hs_hosting_asset WHERE uuid = NEW.parentAssetUuid INTO newParentAsset; + perform createRoleWithGrants( hsHostingAssetOWNER(NEW), permissions => array['DELETE'], - incomingSuperRoles => array[hsBookingItemADMIN(newBookingItem)] + incomingSuperRoles => array[ + hsBookingItemADMIN(newBookingItem), + hsHostingAssetADMIN(newParentAsset)] ); perform createRoleWithGrants( hsHostingAssetADMIN(NEW), permissions => array['UPDATE'], - incomingSuperRoles => array[hsHostingAssetOWNER(NEW)] + incomingSuperRoles => array[ + hsBookingItemAGENT(newBookingItem), + hsHostingAssetAGENT(newParentAsset), + hsHostingAssetOWNER(NEW)] + ); + + perform createRoleWithGrants( + hsHostingAssetAGENT(NEW), + incomingSuperRoles => array[hsHostingAssetADMIN(NEW)] ); perform createRoleWithGrants( hsHostingAssetTENANT(NEW), permissions => array['SELECT'], - incomingSuperRoles => array[hsHostingAssetADMIN(NEW)], - outgoingSubRoles => array[hsBookingItemTENANT(newBookingItem)] + incomingSuperRoles => array[hsHostingAssetAGENT(NEW)], + outgoingSubRoles => array[ + hsBookingItemTENANT(newBookingItem), + hsHostingAssetTENANT(newParentAsset)] ); - IF NEW.type = 'CLOUD_SERVER' THEN - ELSIF NEW.type = 'MANAGED_SERVER' THEN - ELSIF NEW.type = 'MANAGED_WEBSPACE' THEN - ELSE - END IF; - call leaveTriggerForObjectUuid(NEW.uuid); end; $$; @@ -92,6 +98,49 @@ execute procedure insertTriggerForHsHostingAsset_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_booking_item ---------------------------- /* @@ -162,49 +211,6 @@ create trigger z_new_hs_hosting_asset_grants_insert_to_hs_hosting_asset_tg for each row execute procedure new_hs_hosting_asset_grants_insert_to_hs_hosting_asset_tf(); --- 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(); - -- ============================================================================ --changeset hs_hosting_asset-rbac-CHECKING-INSERT-PERMISSION:1 endDelimiter:--// @@ -219,16 +225,16 @@ create or replace function hs_hosting_asset_insert_permission_check_tf() 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.bookingItemUuid - if NEW.type in ('MANAGED_SERVER', 'CLOUD_SERVER', 'MANAGED_WEBSPACE') and hasInsertPermission(NEW.bookingItemUuid, 'hs_hosting_asset') then + if hasInsertPermission(NEW.bookingItemUuid, 'hs_hosting_asset') then return NEW; end if; -- check INSERT permission via direct foreign key: NEW.parentAssetUuid - if NEW.type in ('MANAGED_WEBSPACE') and hasInsertPermission(NEW.parentAssetUuid, 'hs_hosting_asset') then - return NEW; - end if; - -- check INSERT INSERT if global ADMIN - if isGlobalAdmin() then + if hasInsertPermission(NEW.parentAssetUuid, 'hs_hosting_asset') then return NEW; end if; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemControllerAcceptanceTest.java index b0d9794e..7f385824 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemControllerAcceptanceTest.java @@ -4,7 +4,9 @@ import io.hypersistence.utils.hibernate.type.range.Range; import io.restassured.RestAssured; import io.restassured.http.ContentType; import net.hostsharing.hsadminng.HsadminNgApplication; +import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectEntity; import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRepository; +import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.JpaAttempt; @@ -23,6 +25,7 @@ import java.util.Map; import java.util.UUID; import static java.util.Map.entry; +import static java.util.Optional.ofNullable; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_WEBSPACE; import static net.hostsharing.hsadminng.rbac.test.JsonMatcher.lenientlyEquals; import static org.assertj.core.api.Assertions.assertThat; @@ -78,9 +81,21 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup .contentType("application/json") .body("", lenientlyEquals(""" [ + { + "type": "MANAGED_WEBSPACE", + "caption": "some ManagedWebspace", + "validFrom": "2022-10-01", + "validTo": null, + "resources": { + "SDD": 512, + "Multi": 4, + "Daemons": 2, + "Traffic": 12 + } + }, { "type": "MANAGED_SERVER", - "caption": "some ManagedServer", + "caption": "separate ManagedServer", "validFrom": "2022-10-01", "validTo": null, "resources": { @@ -90,18 +105,6 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "Traffic": 42 } }, - { - "type": "CLOUD_SERVER", - "caption": "some CloudServer", - "validFrom": "2023-01-15", - "validTo": "2024-04-14", - "resources": { - "HDD": 1024, - "RAM": 4, - "CPUs": 2, - "Traffic": 42 - } - }, { "type": "PRIVATE_CLOUD", "caption": "some PrivateCloud", @@ -178,8 +181,8 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup void globalAdmin_canGetArbitraryBookingItem() { context.define("superuser-alex@hostsharing.net"); final var givenBookingItemUuid = bookingItemRepo.findAll().stream() - .filter(bi -> bi.getProject().getDebitor().getDebitorNumber() == 1000111) - .filter(item -> item.getCaption().equals("some CloudServer")) + .filter(bi -> belongsToDebitorNumber(bi, 1000111)) + .filter(item -> item.getCaption().equals("some ManagedWebspace")) .findAny().orElseThrow().getUuid(); RestAssured // @formatter:off @@ -193,14 +196,15 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup .contentType("application/json") .body("", lenientlyEquals(""" { - "caption": "some CloudServer", - "validFrom": "2023-01-15", - "validTo": "2024-04-14", - "resources": { - "HDD": 1024, - "RAM": 4, - "CPUs": 2, - "Traffic": 42 + "type": "MANAGED_WEBSPACE", + "caption": "some ManagedWebspace", + "validFrom": "2022-10-01", + "validTo": null, + "resources": { + "SDD": 512, + "Multi": 4, + "Daemons": 2, + "Traffic": 12 } } """)); // @formatter:on @@ -210,7 +214,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup void normalUser_canNotGetUnrelatedBookingItem() { context.define("superuser-alex@hostsharing.net"); final var givenBookingItemUuid = bookingItemRepo.findAll().stream() - .filter(bi -> bi.getProject().getDebitor().getDebitorNumber() == 1000212) + .filter(bi -> belongsToDebitorNumber(bi, 1000212)) .map(HsBookingItemEntity::getUuid) .findAny().orElseThrow(); @@ -228,8 +232,8 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup void debitorAgentUser_canGetRelatedBookingItem() { context.define("superuser-alex@hostsharing.net"); final var givenBookingItemUuid = bookingItemRepo.findAll().stream() - .filter(bi -> bi.getProject().getDebitor().getDebitorNumber() == 1000313) - .filter(item -> item.getCaption().equals("some CloudServer")) + .filter(bi -> belongsToDebitorNumber(bi, 1000313)) + .filter(item -> item.getCaption().equals("separate ManagedServer")) .findAny().orElseThrow().getUuid(); RestAssured // @formatter:off @@ -243,18 +247,28 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup .contentType("application/json") .body("", lenientlyEquals(""" { - "caption": "some CloudServer", - "validFrom": "2023-01-15", - "validTo": "2024-04-14", + "type": "MANAGED_SERVER", + "caption": "separate ManagedServer", + "validFrom": "2022-10-01", + "validTo": null, "resources": { - "HDD": 1024, - "RAM": 4, + "RAM": 8, + "SDD": 512, "CPUs": 2, "Traffic": 42 } } """)); // @formatter:on } + + private static boolean belongsToDebitorNumber(final HsBookingItemEntity bi, final int i) { + return ofNullable(bi) + .map(HsBookingItemEntity::getProject) + .map(HsBookingProjectEntity::getDebitor) + .map(HsOfficeDebitorEntity::getDebitorNumber) + .filter(debitorNumber -> debitorNumber == i) + .isPresent(); + } } @Nested diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemRepositoryIntegrationTest.java index ce69ee98..f4ac6fee 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemRepositoryIntegrationTest.java @@ -119,34 +119,34 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup final var all = rawRoleRepo.findAll(); assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from( initialRoleNames, - "hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:ADMIN", - "hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:AGENT", - "hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:OWNER", - "hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:TENANT")); + "hs_booking_item#somenewbookingitem:ADMIN", + "hs_booking_item#somenewbookingitem:AGENT", + "hs_booking_item#somenewbookingitem:OWNER", + "hs_booking_item#somenewbookingitem:TENANT")); assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())) .map(s -> s.replace("hs_office_", "")) .containsExactlyInAnyOrder(fromFormatted( initialGrantNames, // global-admin - "{ grant perm:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:DELETE to role:global#global:ADMIN by system and assume }", + "{ grant perm:hs_booking_item#somenewbookingitem:INSERT>hs_booking_item to role:hs_booking_item#somenewbookingitem:ADMIN by system and assume }", + "{ grant perm:hs_booking_item#somenewbookingitem:DELETE to role:global#global:ADMIN by system and assume }", // owner - "{ grant role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:OWNER to role:hs_booking_project#D-1000111-D-1000111defaultproject:AGENT by system and assume }", + "{ grant role:hs_booking_item#somenewbookingitem:OWNER to role:hs_booking_project#D-1000111-D-1000111defaultproject:AGENT by system and assume }", // admin - "{ grant perm:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:UPDATE to role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:ADMIN by system and assume }", - "{ grant role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:ADMIN to role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:OWNER by system and assume }", - "{ grant perm:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:INSERT>hs_hosting_asset to role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:AGENT by system and assume }", + "{ grant perm:hs_booking_item#somenewbookingitem:UPDATE to role:hs_booking_item#somenewbookingitem:ADMIN by system and assume }", + "{ grant role:hs_booking_item#somenewbookingitem:ADMIN to role:hs_booking_item#somenewbookingitem:OWNER by system and assume }", + "{ grant perm:hs_booking_item#somenewbookingitem:INSERT>hs_hosting_asset to role:hs_booking_item#somenewbookingitem:AGENT by system and assume }", // agent - "{ grant role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:ADMIN to role:hs_booking_project#D-1000111-D-1000111defaultproject:AGENT by system and assume }", - "{ grant role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:AGENT to role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:ADMIN by system and assume }", + "{ grant role:hs_booking_item#somenewbookingitem:AGENT to role:hs_booking_item#somenewbookingitem:ADMIN by system and assume }", // tenant - "{ grant role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:TENANT to role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:AGENT by system and assume }", - "{ grant perm:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:SELECT to role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:TENANT by system and assume }", - "{ grant role:hs_booking_project#D-1000111-D-1000111defaultproject:TENANT to role:hs_booking_item#D-1000111-D-1000111defaultproject-somenewbookingitem:TENANT by system and assume }", + "{ grant role:hs_booking_item#somenewbookingitem:TENANT to role:hs_booking_item#somenewbookingitem:AGENT by system and assume }", + "{ grant perm:hs_booking_item#somenewbookingitem:SELECT to role:hs_booking_item#somenewbookingitem:TENANT by system and assume }", + "{ grant role:hs_booking_project#D-1000111-D-1000111defaultproject:TENANT to role:hs_booking_item#somenewbookingitem:TENANT by system and assume }", null)); } @@ -174,8 +174,8 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup // then allTheseBookingItemsAreReturned( result, - "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), some ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })", - "HsBookingItemEntity(D-1000212:D-1000212 default project, CLOUD_SERVER, [2023-01-15,2024-04-15), some CloudServer, { CPUs: 2, HDD: 1024, RAM: 4, Traffic: 42 })", + "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })", + "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SDD: 512, Traffic: 12 })", "HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10240, SDD: 10240, Traffic: 42 })"); } @@ -194,8 +194,8 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup // then: exactlyTheseBookingItemsAreReturned( result, - "HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), some ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })", - "HsBookingItemEntity(D-1000111:D-1000111 default project, CLOUD_SERVER, [2023-01-15,2024-04-15), some CloudServer, { CPUs: 2, HDD: 1024, RAM: 4, Traffic: 42 })", + "HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })", + "HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SDD: 512, Traffic: 12 })", "HsBookingItemEntity(D-1000111:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10240, SDD: 10240, Traffic: 42 })"); } } @@ -206,7 +206,7 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup @Test public void hostsharingAdmin_canUpdateArbitraryBookingItem() { // given - final var givenBookingItemUuid = givenSomeTemporaryBookingItem(1000111).getUuid(); + final var givenBookingItemUuid = givenSomeTemporaryBookingItem("D-1000111 default project").getUuid(); // when final var result = jpaAttempt.transacted(() -> { @@ -242,7 +242,7 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup public void globalAdmin_withoutAssumedRole_canDeleteAnyBookingItem() { // given context("superuser-alex@hostsharing.net", null); - final var givenBookingItem = givenSomeTemporaryBookingItem(1000111); + final var givenBookingItem = givenSomeTemporaryBookingItem("D-1000111 default project"); // when final var result = jpaAttempt.transacted(() -> { @@ -262,7 +262,7 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup public void nonGlobalAdmin_canNotDeleteTheirRelatedBookingItem() { // given context("superuser-alex@hostsharing.net", null); - final var givenBookingItem = givenSomeTemporaryBookingItem(1000111); + final var givenBookingItem = givenSomeTemporaryBookingItem("D-1000111 default project"); // when final var result = jpaAttempt.transacted(() -> { @@ -288,7 +288,7 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup context("superuser-alex@hostsharing.net"); final var initialRoleNames = Array.from(distinctRoleNamesOf(rawRoleRepo.findAll())); final var initialGrantNames = Array.from(distinctGrantDisplaysOf(rawGrantRepo.findAll())); - final var givenBookingItem = givenSomeTemporaryBookingItem(1000111); + final var givenBookingItem = givenSomeTemporaryBookingItem("D-1000111 default project"); // when final var result = jpaAttempt.transacted(() -> { @@ -323,11 +323,12 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup "[creating booking-item test-data 1000313, hs_booking_item, INSERT]"); } - private HsBookingItemEntity givenSomeTemporaryBookingItem(final int debitorNumber) { + private HsBookingItemEntity givenSomeTemporaryBookingItem(final String projectCaption) { return jpaAttempt.transacted(() -> { context("superuser-alex@hostsharing.net"); - final var givenDebitor = debitorRepo.findDebitorByDebitorNumber(debitorNumber).get(0); - final var givenProject = projectRepo.findAllByDebitorUuid(givenDebitor.getUuid()).get(0); + final var givenProject = projectRepo.findAll().stream() + .filter(p -> p.getCaption().equals(projectCaption)) + .findAny().orElseThrow(); final var newBookingItem = HsBookingItemEntity.builder() .project(givenProject) .type(MANAGED_SERVER) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/project/HsBookingProjectRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/project/HsBookingProjectRepositoryIntegrationTest.java index 69cb83dd..edc4649a 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/project/HsBookingProjectRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/project/HsBookingProjectRepositoryIntegrationTest.java @@ -125,7 +125,6 @@ class HsBookingProjectRepositoryIntegrationTest extends ContextBasedTestWithClea "{ grant perm:hs_booking_project#D-1000111-somenewbookingproject:INSERT>hs_booking_item to role:hs_booking_project#D-1000111-somenewbookingproject:ADMIN by system and assume }", // agent - "{ grant role:hs_booking_project#D-1000111-somenewbookingproject:ADMIN to role:relation#FirstGmbH-with-DEBITOR-FirstGmbH:AGENT by system and assume }", "{ grant role:hs_booking_project#D-1000111-somenewbookingproject:OWNER to role:relation#FirstGmbH-with-DEBITOR-FirstGmbH:AGENT by system and assume }", "{ grant role:hs_booking_project#D-1000111-somenewbookingproject:TENANT to role:hs_booking_project#D-1000111-somenewbookingproject:AGENT by system and assume }", diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java index 64c98006..6e02e719 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java @@ -8,7 +8,6 @@ import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository; import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectEntity; import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRepository; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; -import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import org.junit.jupiter.api.Nested; @@ -169,7 +168,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup } @Nested - class AddServer { + class AddAsset { @Test void globalAdmin_canAddBookedAsset() { @@ -221,11 +220,11 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup context.define("person-FirbySusan@example.com"); - generateRbacDiagramForCurrentSubjects(RbacGrantsDiagramService.Include.ALL_NON_TEST_ENTITY_RELATED, "parentAssetAgent_canAddSubAsset"); // FIXME - final var location = RestAssured // @formatter:off .given() - .header("current-user", "person-FirbySusan@example.com") + //.header("current-user", "superuser-alex@hostsharing.net", "hs_hosting_asset#"+givenParentAsset.getIdentifier()+":ADMIN") + .header("current-user", "superuser-alex@hostsharing.net") + .header("assumed-roles", "hs_hosting_asset#vm1011:ADMIN") .contentType(ContentType.JSON) .body(""" { @@ -419,7 +418,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup context.define("superuser-alex@hostsharing.net"); assertThat(assetRepo.findByUuid(givenAsset.getUuid())).isPresent().get() .matches(asset -> { - assertThat(asset.toString()).isEqualTo("HsHostingAssetEntity(CLOUD_SERVER, vm2001, some test-asset, D-1000111:D-1000111 default project:some CloudServer, { CPUs: 2, RAM: 100, SSD: 250, Traffic: 2000 })"); + assertThat(asset.toString()).isEqualTo("HsHostingAssetEntity(CLOUD_SERVER, vm2001, some test-asset, D-1000111:D-1000111 default project:test CloudServer, { CPUs: 2, RAM: 100, SSD: 250, Traffic: 2000 })"); return true; }); } @@ -459,7 +458,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup .port(port) .when() .delete("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid()) - .then().log().body().assertThat() + .then().log().all().assertThat() .statusCode(404); // @formatter:on // then the given asset is still there @@ -468,16 +467,16 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup } HsBookingItemEntity givenBookingItem(final String projectCaption, final String bookingItemCaption) { - final var givenProject = projectRepo.findAll().stream() - .filter(p -> p.getCaption().equals(projectCaption)) - .findAny().orElseThrow(); - return bookingItemRepo.findAllByProjectUuid(givenProject.getUuid()).stream() - .filter(i -> i.getCaption().equals(bookingItemCaption)) + return bookingItemRepo.findAll().stream() + .filter(a -> ofNullable(a) + .filter(bi -> bi.getCaption().equals(bookingItemCaption)) + .isPresent()) .findAny().orElseThrow(); } HsHostingAssetEntity givenParentAsset(final String projectCaption, final HsHostingAssetType assetType) { final var givenAsset = assetRepo.findAll().stream() + .filter(a -> a.getType() == assetType) .filter(a -> ofNullable(a) .map(HsHostingAssetEntity::getBookingItem) .map(HsBookingItemEntity::getProject) @@ -496,7 +495,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup context.define("superuser-alex@hostsharing.net"); final var newAsset = HsHostingAssetEntity.builder() .uuid(UUID.randomUUID()) - .bookingItem(givenBookingItem("D-1000111 default project", "some CloudServer")) + .bookingItem(givenBookingItem("D-1000111 default project", "test CloudServer")) .type(hostingAssetType) .identifier("vm" + identifierSuffix) .caption("some test-asset") 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 933cf468..08e67751 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 @@ -121,8 +121,9 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu final var all = rawRoleRepo.findAll(); assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from( initialRoleNames, - "hs_hosting_asset#vm9000:ADMIN", "hs_hosting_asset#vm9000:OWNER", + "hs_hosting_asset#vm9000:ADMIN", + "hs_hosting_asset#vm9000:AGENT", "hs_hosting_asset#vm9000:TENANT")); assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())) .map(s -> s.replace("hs_office_", "")) @@ -130,18 +131,20 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu initialGrantNames, // owner - "{ grant role:hs_hosting_asset#vm9000:OWNER to role:hs_booking_item#D-1000111-D-1000111defaultproject-somePrivateCloud:ADMIN by system and assume }", + "{ grant role:hs_hosting_asset#vm9000:OWNER to role:hs_booking_item#somePrivateCloud:ADMIN by system and assume }", "{ grant perm:hs_hosting_asset#vm9000:DELETE to role:hs_hosting_asset#vm9000:OWNER by system and assume }", "{ grant role:hs_hosting_asset#vm9000:ADMIN to role:hs_hosting_asset#vm9000:OWNER by system and assume }", // admin "{ grant perm:hs_hosting_asset#vm9000:INSERT>hs_hosting_asset to role:hs_hosting_asset#vm9000:ADMIN by system and assume }", "{ grant perm:hs_hosting_asset#vm9000:UPDATE to role:hs_hosting_asset#vm9000:ADMIN by system and assume }", - "{ grant role:hs_hosting_asset#vm9000:TENANT to role:hs_hosting_asset#vm9000:ADMIN by system and assume }", + "{ grant role:hs_hosting_asset#vm9000:ADMIN to role:hs_booking_item#somePrivateCloud:AGENT by system and assume }", + "{ grant role:hs_hosting_asset#vm9000:TENANT to role:hs_hosting_asset#vm9000:AGENT by system and assume }", + "{ grant role:hs_hosting_asset#vm9000:AGENT to role:hs_hosting_asset#vm9000:ADMIN by system and assume }", // tenant "{ grant perm:hs_hosting_asset#vm9000:SELECT to role:hs_hosting_asset#vm9000:TENANT by system and assume }", - "{ grant role:hs_booking_item#D-1000111-D-1000111defaultproject-somePrivateCloud:TENANT to role:hs_hosting_asset#vm9000:TENANT by system and assume }", + "{ grant role:hs_booking_item#somePrivateCloud:TENANT to role:hs_hosting_asset#vm9000:TENANT by system and assume }", null)); } @@ -166,28 +169,27 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu // then allTheseServersAreReturned( result, - "HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:some ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })", - "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:some ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })", - "HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:some ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })"); + "HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })", + "HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })", + "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })"); } @Test public void normalUser_canViewOnlyRelatedAsset() { // given: context("person-FirbySusan@example.com"); - context("superuser-alex@hostsharing.net"); // FIXME + // context("superuser-alex@hostsharing.net"); // FIXME final var projectUuid = projectRepo.findAll().stream() .filter(p -> p.getCaption().equals("D-1000111 default project")) .findAny().orElseThrow().getUuid(); // when: - // FIXME generateRbacDiagramForCurrentSubjects(RbacGrantsDiagramService.Include.ALL_NON_TEST_ENTITY_RELATED, "normalUser_canViewOnlyRelatedAsset"); final var result = assetRepo.findAllByCriteria(projectUuid, null, null); // then: exactlyTheseAssetsAreReturned( result, - "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:some ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })", + "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })", "HsHostingAssetEntity(MANAGED_SERVER, vm1011, some ManagedServer, D-1000111:D-1000111 default project:some PrivateCloud, { CPU: 2, SDD: 512, extra: 42 })", "HsHostingAssetEntity(CLOUD_SERVER, vm2011, another CloudServer, D-1000111:D-1000111 default project:some PrivateCloud, { CPU: 2, HDD: 1024, extra: 42 })"); } @@ -205,7 +207,7 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu // then allTheseServersAreReturned( result, - "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:some ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })"); + "HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedServer, { HDD: 2048, RAM: 1, SDD: 512, extra: 42 })"); } } @@ -356,7 +358,7 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu private HsHostingAssetEntity givenSomeTemporaryAsset(final String projectCaption, final String identifier) { return jpaAttempt.transacted(() -> { context("superuser-alex@hostsharing.net"); - final var givenBookingItem = givenBookingItem(projectCaption, "some CloudServer"); + final var givenBookingItem = givenBookingItem("D-1000111 default project", "some PrivateCloud"); final var newAsset = HsHostingAssetEntity.builder() .bookingItem(givenBookingItem) .type(CLOUD_SERVER)