Merge remote-tracking branch 'origin/master' into structured-liquibase-files

# Conflicts:
#	README.md
#	doc/rbac.md
#	src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java
#	src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java
#	src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java
#	src/main/resources/db/changelog/1-rbac/1080-rbac-global.sql
#	src/main/resources/db/changelog/133-test-domain-rbac.md
#	src/main/resources/db/changelog/223-hs-office-relation-rbac.md
#	src/main/resources/db/changelog/233-hs-office-partner-rbac.md
#	src/main/resources/db/changelog/253-hs-office-sepamandate-rbac.md
#	src/main/resources/db/changelog/273-hs-office-debitor-rbac.md
#	src/main/resources/db/changelog/303-hs-office-membership-rbac.md
#	src/main/resources/db/changelog/313-hs-office-coopshares-rbac.md
#	src/main/resources/db/changelog/313-hs-office-coopshares-rbac.sql
#	src/main/resources/db/changelog/323-hs-office-coopassets-rbac.md
#	src/main/resources/db/changelog/323-hs-office-coopassets-rbac.sql
#	src/main/resources/db/changelog/5-hs-office/510-membership/5103-hs-office-membership-rbac.sql
#	src/test/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepositoryIntegrationTest.java
#	src/test/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionRepositoryIntegrationTest.java
#	src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipControllerAcceptanceTest.java
#	src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java
#	src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java
#	src/test/java/net/hostsharing/hsadminng/rbac/rbacrole/TestRbacRole.java
This commit is contained in:
Michael Hoennig 2024-04-02 12:11:45 +02:00
commit fc4bc0bc04
10 changed files with 78 additions and 48 deletions

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:
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
# add a new customer

View File

@ -206,7 +206,7 @@ and the *role-stereotype* describes a role relative to a referenced business-obj
#### owner
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.
@ -470,14 +470,14 @@ together {
permCustomerXyzSELECT--> boCustXyz
}
entity "Role customer#xyz:tenant" as roleCustXyzTenant
entity "Role customer#xyz:TENANT" as roleCustXyzTenant
roleCustXyzTenant --> permCustomerXyzSELECT
entity "Role customer#xyz:admin" as roleCustXyzAdmin
entity "Role customer#xyz:ADMIN" as roleCustXyzAdmin
roleCustXyzAdmin --> roleCustXyzTenant
roleCustXyzAdmin --> permCustomerXyzINSERT:package
entity "Role customer#xyz:owner" as roleCustXyzOwner
entity "Role customer#xyz:OWNER" as roleCustXyzOwner
roleCustXyzOwner ..> roleCustXyzAdmin
roleCustXyzOwner --> permCustomerXyzDELETE
@ -493,7 +493,7 @@ actorHostmaster --> roleAdmins
```
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.
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 {
entity "Role customer#xyz:tenant" as roleCustXyzTenant
entity "Role customer#xyz:admin" as roleCustXyzAdmin
entity "Role customer#xyz:owner" as roleCustXyzOwner
entity "Role customer#xyz:TENANT" as roleCustXyzTenant
entity "Role customer#xyz:ADMIN" as roleCustXyzAdmin
entity "Role customer#xyz:OWNER" as roleCustXyzOwner
}
package {
entity "Role package#xyz00:owner" as rolePacXyz00Owner
entity "Role package#xyz00:admin" as rolePacXyz00Admin
entity "Role package#xyz00:tenant" as rolePacXyz00Tenant
entity "Role package#xyz00:OWNER" as rolePacXyz00Owner
entity "Role package#xyz00:ADMIN" as rolePacXyz00Admin
entity "Role package#xyz00:TENANT" as rolePacXyz00Tenant
}
rolePacXyz00Tenant --> permPacXyz00SELECT

View File

@ -1,7 +1,11 @@
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.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.persistence.HasUuid;
@ -10,7 +14,16 @@ import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
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.math.BigDecimal;
import java.time.LocalDate;
@ -20,8 +33,11 @@ import java.util.UUID;
import static java.util.Optional.ofNullable;
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.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.AGENT;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.directlyFetchedByDependsOnColumn;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
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(UPDATE)
.toRole("membership", ADMIN).grantPermission(SELECT);
.toRole("membership", AGENT).grantPermission(SELECT);
}
public static void main(String[] args) throws IOException {

View File

@ -1,6 +1,10 @@
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.hs.office.membership.HsOfficeMembershipEntity;
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.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.time.LocalDate;
import java.util.UUID;
@ -17,9 +30,11 @@ import java.util.UUID;
import static java.util.Optional.ofNullable;
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.Permission.*;
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.rbacViewFor;
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(UPDATE)
.toRole("membership", ADMIN).grantPermission(SELECT);
.toRole("membership", AGENT).grantPermission(SELECT);
}
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.AGENT;
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.SQL.fetchedBySql;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
@ -145,14 +145,14 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
.createRole(OWNER, (with) -> {
with.owningUser(CREATOR);
with.incomingSuperRole("partnerRel", ADMIN);
with.permission(DELETE);
})
.createSubRole(ADMIN, (with) -> {
with.incomingSuperRole("partnerRel", AGENT);
with.incomingSuperRole("partnerRel", ADMIN);
with.permission(DELETE);
with.permission(UPDATE);
})
.createSubRole(REFERRER, (with) -> {
.createSubRole(AGENT, (with) -> {
with.incomingSuperRole("partnerRel", AGENT);
with.outgoingSubRole("partnerRel", TENANT);
with.permission(SELECT);
});

View File

@ -112,7 +112,7 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted(
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 }",
null));
}

View File

@ -111,7 +111,7 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted(
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 }",
null));
}

View File

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

View File

@ -110,9 +110,9 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
final var all = rawRoleRepo.findAll();
assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from(
initialRoleNames,
"hs_office_membership#M-1000117:ADMIN",
"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()))
.map(s -> s.replace("hs_office_", ""))
.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 }",
// 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
"{ 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:OWNER 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 }",
"{ 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:relation#HostsharingeG-with-PARTNER-FirstGmbH:ADMIN by system and assume }",
// 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 perm:membership#M-1000117:SELECT to role:membership#M-1000117:REFERRER 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 }",
"{ grant role:membership#M-1000117:AGENT to role:relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT by system and assume }",
"{ grant role:relation#HostsharingeG-with-PARTNER-FirstGmbH:TENANT to role:membership#M-1000117:AGENT by system and assume }",
null));
}
@ -224,20 +223,20 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
}
@Test
public void membershipReferrer_canViewButNotUpdateRelatedMembership() {
public void membershipAgent_canViewButNotUpdateRelatedMembership() {
// given
context("superuser-alex@hostsharing.net");
final var givenMembership = givenSomeTemporaryMembership("First", "13");
assertThatMembershipExistsAndIsAccessibleToCurrentContext(givenMembership);
assertThatMembershipIsVisibleForRole(
givenMembership,
"hs_office_membership#M-1000113:REFERRER");
"hs_office_membership#M-1000113:AGENT");
final var newValidityEnd = LocalDate.now();
// when
final var result = jpaAttempt.transacted(() -> {
// 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(
Range.closedOpen(givenMembership.getValidity().lower(), newValidityEnd));
return membershipRepo.save(givenMembership);

View File

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