structured-liquibase-files #29

Merged
hsh-michaelhoennig merged 11 commits from structured-liquibase-files into master 2024-04-02 12:29:32 +02:00
10 changed files with 78 additions and 48 deletions
Showing only changes of commit fc4bc0bc04 - Show all commits

View File

@ -82,7 +82,7 @@ If you have at least Docker and the Java JDK installed in appropriate versions a
# the following command should return a JSON array with just all packages visible for the admin of the customer yyy: # the following command should return a JSON array with just all packages visible for the admin of the customer yyy:
curl \ curl \
-H 'current-user: superuser-alex@hostsharing.net' -H 'assumed-roles: test_customer#yyy:admin' \ -H 'current-user: superuser-alex@hostsharing.net' -H 'assumed-roles: test_customer#yyy:ADMIN' \
http://localhost:8080/api/test/packages http://localhost:8080/api/test/packages
# add a new customer # add a new customer

View File

@ -206,7 +206,7 @@ and the *role-stereotype* describes a role relative to a referenced business-obj
#### owner #### owner
The owner-role is granted to the subject which created the business object. The owner-role is granted to the subject which created the business object.
E.g. for a new *customer* it would be granted to 'administrators' and for a new *package* to the 'customer#...:admin'. E.g. for a new *customer* it would be granted to 'administrators' and for a new *package* to the 'customer#...:ADMIN'.
Whoever has the owner-role assigned can do everything with the related business-object, including deleting (or deactivating) it. Whoever has the owner-role assigned can do everything with the related business-object, including deleting (or deactivating) it.
@ -470,14 +470,14 @@ together {
permCustomerXyzSELECT--> boCustXyz permCustomerXyzSELECT--> boCustXyz
} }
entity "Role customer#xyz:tenant" as roleCustXyzTenant entity "Role customer#xyz:TENANT" as roleCustXyzTenant
roleCustXyzTenant --> permCustomerXyzSELECT roleCustXyzTenant --> permCustomerXyzSELECT
entity "Role customer#xyz:admin" as roleCustXyzAdmin entity "Role customer#xyz:ADMIN" as roleCustXyzAdmin
roleCustXyzAdmin --> roleCustXyzTenant roleCustXyzAdmin --> roleCustXyzTenant
roleCustXyzAdmin --> permCustomerXyzINSERT:package roleCustXyzAdmin --> permCustomerXyzINSERT:package
entity "Role customer#xyz:owner" as roleCustXyzOwner entity "Role customer#xyz:OWNER" as roleCustXyzOwner
roleCustXyzOwner ..> roleCustXyzAdmin roleCustXyzOwner ..> roleCustXyzAdmin
roleCustXyzOwner --> permCustomerXyzDELETE roleCustXyzOwner --> permCustomerXyzDELETE
@ -493,7 +493,7 @@ actorHostmaster --> roleAdmins
``` ```
As you can see, there something special: As you can see, there something special:
From the 'Role customer#xyz:owner' to the 'Role customer#xyz:admin' there is a dashed line, whereas all other lines are solid lines. From the 'Role customer#xyz:OWNER' to the 'Role customer#xyz:admin' there is a dashed line, whereas all other lines are solid lines.
Solid lines means, that one role is granted to another and automatically assumed in all queries to the restricted views. Solid lines means, that one role is granted to another and automatically assumed in all queries to the restricted views.
The dashed line means that one role is granted to another but not automatically assumed in queries to the restricted views. The dashed line means that one role is granted to another but not automatically assumed in queries to the restricted views.
@ -541,15 +541,15 @@ together {
} }
package { package {
entity "Role customer#xyz:tenant" as roleCustXyzTenant entity "Role customer#xyz:TENANT" as roleCustXyzTenant
entity "Role customer#xyz:admin" as roleCustXyzAdmin entity "Role customer#xyz:ADMIN" as roleCustXyzAdmin
entity "Role customer#xyz:owner" as roleCustXyzOwner entity "Role customer#xyz:OWNER" as roleCustXyzOwner
} }
package { package {
entity "Role package#xyz00:owner" as rolePacXyz00Owner entity "Role package#xyz00:OWNER" as rolePacXyz00Owner
entity "Role package#xyz00:admin" as rolePacXyz00Admin entity "Role package#xyz00:ADMIN" as rolePacXyz00Admin
entity "Role package#xyz00:tenant" as rolePacXyz00Tenant entity "Role package#xyz00:TENANT" as rolePacXyz00Tenant
} }
rolePacXyz00Tenant --> permPacXyz00SELECT rolePacXyz00Tenant --> permPacXyz00SELECT

View File

@ -1,7 +1,11 @@
package net.hostsharing.hsadminng.hs.office.coopassets; package net.hostsharing.hsadminng.hs.office.coopassets;
import lombok.*; import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.persistence.HasUuid;
@ -10,7 +14,16 @@ import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import jakarta.persistence.*; import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.io.IOException;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
@ -20,8 +33,11 @@ import java.util.UUID;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
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.ADMIN;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@ -109,7 +125,7 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable, HasUu
.toRole("membership", ADMIN).grantPermission(INSERT) .toRole("membership", ADMIN).grantPermission(INSERT)
.toRole("membership", ADMIN).grantPermission(UPDATE) .toRole("membership", ADMIN).grantPermission(UPDATE)
.toRole("membership", ADMIN).grantPermission(SELECT); .toRole("membership", AGENT).grantPermission(SELECT);
} }
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {

View File

@ -1,6 +1,10 @@
package net.hostsharing.hsadminng.hs.office.coopshares; package net.hostsharing.hsadminng.hs.office.coopshares;
import lombok.*; import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.persistence.HasUuid;
@ -9,7 +13,16 @@ import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.stringify.Stringifyable;
import jakarta.persistence.*; import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.io.IOException;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
@ -17,9 +30,11 @@ import java.util.UUID;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Column.dependsOnColumn;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NOT_NULL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
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.Role.*; 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.SQL.directlyFetchedByDependsOnColumn; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@ -105,7 +120,7 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable, HasUu
.toRole("membership", ADMIN).grantPermission(INSERT) .toRole("membership", ADMIN).grantPermission(INSERT)
.toRole("membership", ADMIN).grantPermission(UPDATE) .toRole("membership", ADMIN).grantPermission(UPDATE)
.toRole("membership", ADMIN).grantPermission(SELECT); .toRole("membership", AGENT).grantPermission(SELECT);
} }
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {

View File

@ -27,7 +27,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN; 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.AGENT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.OWNER; 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;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.TENANT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
@ -145,14 +145,14 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
.createRole(OWNER, (with) -> { .createRole(OWNER, (with) -> {
with.owningUser(CREATOR); with.owningUser(CREATOR);
with.incomingSuperRole("partnerRel", ADMIN);
with.permission(DELETE);
}) })
.createSubRole(ADMIN, (with) -> { .createSubRole(ADMIN, (with) -> {
with.incomingSuperRole("partnerRel", AGENT); with.incomingSuperRole("partnerRel", ADMIN);
with.permission(DELETE);
with.permission(UPDATE); with.permission(UPDATE);
}) })
.createSubRole(REFERRER, (with) -> { .createSubRole(AGENT, (with) -> {
with.incomingSuperRole("partnerRel", AGENT);
with.outgoingSubRole("partnerRel", TENANT); with.outgoingSubRole("partnerRel", TENANT);
with.permission(SELECT); with.permission(SELECT);
}); });

View File

@ -112,7 +112,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", "")) .map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted( .containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, initialGrantNames,
"{ grant perm:coopassetstransaction#temprefB:SELECT to role:membership#M-1000101:ADMIN by system and assume }", "{ grant perm:coopassetstransaction#temprefB:SELECT to role:membership#M-1000101:AGENT by system and assume }",
"{ grant perm:coopassetstransaction#temprefB:UPDATE to role:membership#M-1000101:ADMIN by system and assume }", "{ grant perm:coopassetstransaction#temprefB:UPDATE to role:membership#M-1000101:ADMIN by system and assume }",
null)); null));
} }

View File

@ -111,7 +111,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", "")) .map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted( .containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, initialGrantNames,
"{ grant perm:coopsharestransaction#temprefB:SELECT to role:membership#M-1000101:ADMIN by system and assume }", "{ grant perm:coopsharestransaction#temprefB:SELECT to role:membership#M-1000101:AGENT by system and assume }",
"{ grant perm:coopsharestransaction#temprefB:UPDATE to role:membership#M-1000101:ADMIN by system and assume }", "{ grant perm:coopsharestransaction#temprefB:UPDATE to role:membership#M-1000101:ADMIN by system and assume }",
null)); null));
} }

View File

@ -335,18 +335,18 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
} }
@Test @Test
void partnerRelAgent_canPatchValidityOfRelatedMembership() { void partnerRelAdmin_canPatchValidityOfRelatedMembership() {
// given // given
final var givenPartnerAgent = "hs_office_relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT"; final var givenPartnerAdmin = "hs_office_relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN";
context.define("superuser-alex@hostsharing.net", givenPartnerAgent); context.define("superuser-alex@hostsharing.net", givenPartnerAdmin);
final var givenMembership = givenSomeTemporaryMembershipBessler("First"); final var givenMembership = givenSomeTemporaryMembershipBessler("First");
// when // when
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("current-user", "superuser-alex@hostsharing.net") .header("current-user", "superuser-alex@hostsharing.net")
.header("assumed-roles", givenPartnerAgent) .header("assumed-roles", givenPartnerAdmin)
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {

View File

@ -110,9 +110,9 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
final var all = rawRoleRepo.findAll(); final var all = rawRoleRepo.findAll();
assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from( assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from(
initialRoleNames, initialRoleNames,
"hs_office_membership#M-1000117:ADMIN",
"hs_office_membership#M-1000117:OWNER", "hs_office_membership#M-1000117:OWNER",
"hs_office_membership#M-1000117:REFERRER")); "hs_office_membership#M-1000117:ADMIN",
"hs_office_membership#M-1000117:AGENT"));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())) assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
.map(s -> s.replace("hs_office_", "")) .map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted( .containsExactlyInAnyOrder(Array.fromFormatted(
@ -122,21 +122,20 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
"{ grant perm:membership#M-1000117:INSERT>coopsharestransaction to role:membership#M-1000117:ADMIN by system and assume }", "{ grant perm:membership#M-1000117:INSERT>coopsharestransaction to role:membership#M-1000117:ADMIN by system and assume }",
// owner // owner
"{ grant perm:membership#M-1000117:DELETE to role:membership#M-1000117:OWNER by system and assume }", "{ grant perm:membership#M-1000117:DELETE to role:membership#M-1000117:ADMIN by system and assume }",
"{ grant role:membership#M-1000117:OWNER to user:superuser-alex@hostsharing.net by membership#M-1000117:OWNER and assume }",
// admin // admin
"{ grant perm:membership#M-1000117:UPDATE to role:membership#M-1000117:ADMIN by system and assume }", "{ grant perm:membership#M-1000117:UPDATE to role:membership#M-1000117:ADMIN by system and assume }",
"{ grant role:membership#M-1000117:ADMIN to role:membership#M-1000117:OWNER by system and assume }", "{ grant role:membership#M-1000117:ADMIN to role:membership#M-1000117:OWNER by system and assume }",
"{ grant role:membership#M-1000117:OWNER to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN by system and assume }", "{ grant role:membership#M-1000117:ADMIN to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN by system and assume }",
"{ grant role:membership#M-1000117:OWNER to user:superuser-alex@hostsharing.net by membership#M-1000117:OWNER and assume }",
// agent // agent
"{ grant role:membership#M-1000117:ADMIN to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT by system and assume }", "{ grant perm:membership#M-1000117:SELECT to role:membership#M-1000117:AGENT by system and assume }",
"{ grant role:membership#M-1000117:AGENT to role:membership#M-1000117:ADMIN by system and assume }",
// referrer "{ grant role:membership#M-1000117:AGENT to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT by system and assume }",
"{ grant perm:membership#M-1000117:SELECT to role:membership#M-1000117:REFERRER by system and assume }", "{ grant role:relation#HostsharingeG-with-PARTNER-FirstGmbH:TENANT to role:membership#M-1000117:AGENT by system and assume }",
"{ grant role:membership#M-1000117:REFERRER to role:membership#M-1000117:ADMIN by system and assume }",
"{ grant role:relation#HostsharingeG-with-PARTNER-FirstGmbH:TENANT to role:membership#M-1000117:REFERRER by system and assume }",
null)); null));
} }
@ -224,20 +223,20 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
} }
@Test @Test
public void membershipReferrer_canViewButNotUpdateRelatedMembership() { public void membershipAgent_canViewButNotUpdateRelatedMembership() {
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenMembership = givenSomeTemporaryMembership("First", "13"); final var givenMembership = givenSomeTemporaryMembership("First", "13");
assertThatMembershipExistsAndIsAccessibleToCurrentContext(givenMembership); assertThatMembershipExistsAndIsAccessibleToCurrentContext(givenMembership);
assertThatMembershipIsVisibleForRole( assertThatMembershipIsVisibleForRole(
givenMembership, givenMembership,
"hs_office_membership#M-1000113:REFERRER"); "hs_office_membership#M-1000113:AGENT");
final var newValidityEnd = LocalDate.now(); final var newValidityEnd = LocalDate.now();
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {
// TODO: we should test with debitor- and partner-admin as well // TODO: we should test with debitor- and partner-admin as well
context("superuser-alex@hostsharing.net", "hs_office_membership#M-1000113:REFERRER"); context("superuser-alex@hostsharing.net", "hs_office_membership#M-1000113:AGENT");
givenMembership.setValidity( givenMembership.setValidity(
Range.closedOpen(givenMembership.getValidity().lower(), newValidityEnd)); Range.closedOpen(givenMembership.getValidity().lower(), newValidityEnd));
return membershipRepo.save(givenMembership); return membershipRepo.save(givenMembership);

View File

@ -507,7 +507,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
}).assertNotNull().returnedValue(); }).assertNotNull().returnedValue();
} }
RbacRoleRvEntity getRbacRoleByName(final String roleName) { RbacRoleEntity getRbacRoleByName(final String roleName) {
return jpaAttempt.transacted(() -> { return jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net", null); context("superuser-alex@hostsharing.net", null);
return rbacRoleRepository.findByRoleName(roleName); return rbacRoleRepository.findByRoleName(roleName);