1
0

RBAC Diagram+PostgreSQL Generator and view->SELECT etc. refactoring (#21)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/21
Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
Michael Hoennig
2024-03-11 12:30:43 +01:00
parent d9558f2cfe
commit 187c0db8e2
91 changed files with 4181 additions and 856 deletions

View File

@ -28,6 +28,7 @@ public class ArchitectureTest {
"..test",
"..test.cust",
"..test.pac",
"..test.dom",
"..context",
"..generated..",
"..persistence..",
@ -49,6 +50,8 @@ public class ArchitectureTest {
"..rbac.rbacuser",
"..rbac.rbacgrant",
"..rbac.rbacrole",
"..rbac.rbacobject",
"..rbac.rbacdef",
"..stringify"
// ATTENTION: Don't simply add packages here, also add arch rules for the new package!
);
@ -116,7 +119,10 @@ public class ArchitectureTest {
public static final ArchRule hsAdminPackagesRule = classes()
.that().resideInAPackage("..hs.office.(*)..")
.should().onlyBeAccessed().byClassesThat()
.resideInAnyPackage("..hs.office.(*)..");
.resideInAnyPackage(
"..hs.office.(*)..",
"..rbac.rbacgrant" // TODO: just because of RbacGrantsDiagramServiceIntegrationTest
);
@ArchTest
@SuppressWarnings("unused")

View File

@ -1,14 +1,37 @@
package net.hostsharing.hsadminng.context;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
@Import(RbacGrantsDiagramService.class)
public abstract class ContextBasedTest {
@Autowired
protected Context context;
@PersistenceContext
protected EntityManager em; // just to be used in subclasses
/**
* To generate a flowchart diagram from the database use something like this in a defined context:
<pre>
RbacGrantsDiagramService.writeToFile(
"title",
diagramService.allGrantsToCurrentUser(of(RbacGrantsDiagramService.Include.USERS, RbacGrantsDiagramService.Include.TEST_ENTITIES, RbacGrantsDiagramService.Include.NOT_ASSUMED, RbacGrantsDiagramService.Include.DETAILS, RbacGrantsDiagramService.Include.PERMISSIONS)),
"filename.md
);
</pre>
*/
@Autowired
protected RbacGrantsDiagramService diagramService; // just to be used in subclasses
TestInfo test;
@BeforeEach

View File

@ -109,7 +109,7 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTestWithC
));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
"{ grant perm delete on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.owner by system and assume }",
"{ grant perm DELETE on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.owner by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.owner to role global#global.admin by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }",
@ -117,7 +117,7 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTestWithC
"{ grant role hs_office_bankaccount#sometempaccC.tenant to role hs_office_bankaccount#sometempaccC.admin by system and assume }",
"{ grant perm view on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.guest by system and assume }",
"{ grant perm SELECT on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.guest by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.guest to role hs_office_bankaccount#sometempaccC.tenant by system and assume }",
null
));

View File

@ -111,11 +111,11 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTestWithClean
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.from(
initialGrantNames,
"{ grant role hs_office_contact#anothernewcontact.owner to role global#global.admin by system and assume }",
"{ grant perm edit on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.admin by system and assume }",
"{ grant perm UPDATE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.admin by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.tenant to role hs_office_contact#anothernewcontact.admin by system and assume }",
"{ grant perm * on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }",
"{ grant perm DELETE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.admin to role hs_office_contact#anothernewcontact.owner by system and assume }",
"{ grant perm view on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.guest by system and assume }",
"{ grant perm SELECT on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.guest by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.guest to role hs_office_contact#anothernewcontact.tenant by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }"
));

View File

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

View File

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

View File

@ -145,8 +145,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
}
@Nested
@Accepts({ "Debitor:C(Create)" })
class CreateDebitor {
class AddDebitor {
@Test
void globalAdmin_withoutAssumedRole_canAddDebitorWithBankAccount() {

View File

@ -118,8 +118,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
});
// then
System.out.println("ok");
// result.assertExceptionWithRootCauseMessage(org.hibernate.exception.ConstraintViolationException.class);
result.assertExceptionWithRootCauseMessage(org.hibernate.exception.ConstraintViolationException.class);
}
@Test
@ -167,12 +166,12 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
.containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
// owner
"{ grant perm * on debitor#1000422:FeG to role debitor#1000422:FeG.owner by system and assume }",
"{ grant perm DELETE on debitor#1000422:FeG to role debitor#1000422:FeG.owner by system and assume }",
"{ grant role debitor#1000422:FeG.owner to role global#global.admin by system and assume }",
"{ grant role debitor#1000422:FeG.owner to user superuser-alex by global#global.admin and assume }",
// admin
"{ grant perm edit on debitor#1000422:FeG to role debitor#1000422:FeG.admin by system and assume }",
"{ grant perm UPDATE on debitor#1000422:FeG to role debitor#1000422:FeG.admin by system and assume }",
"{ grant role debitor#1000422:FeG.admin to role debitor#1000422:FeG.owner by system and assume }",
// agent
@ -187,7 +186,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
"{ grant role partner#10004:FeG.tenant to role debitor#1000422:FeG.tenant by system and assume }",
// guest
"{ grant perm view on debitor#1000422:FeG to role debitor#1000422:FeG.guest by system and assume }",
"{ grant perm SELECT on debitor#1000422:FeG to role debitor#1000422:FeG.guest by system and assume }",
"{ grant role debitor#1000422:FeG.guest to role debitor#1000422:FeG.tenant by system and assume }",
null));

View File

@ -126,11 +126,11 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
initialGrantNames,
// owner
"{ grant perm * on membership#1000117:First to role membership#1000117:First.owner by system and assume }",
"{ grant perm DELETE on membership#1000117:First to role membership#1000117:First.owner by system and assume }",
"{ grant role membership#1000117:First.owner to role global#global.admin by system and assume }",
// admin
"{ grant perm edit on membership#1000117:First to role membership#1000117:First.admin by system and assume }",
"{ grant perm UPDATE on membership#1000117:First to role membership#1000117:First.admin by system and assume }",
"{ grant role membership#1000117:First.admin to role membership#1000117:First.owner by system and assume }",
// agent
@ -149,7 +149,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTestWithCl
"{ grant role membership#1000117:First.tenant to role partner#10001:First.agent by system and assume }",
// guest
"{ grant perm view on membership#1000117:First to role membership#1000117:First.guest by system and assume }",
"{ grant perm SELECT on membership#1000117:First to role membership#1000117:First.guest by system and assume }",
"{ grant role membership#1000117:First.guest to role membership#1000117:First.tenant by system and assume }",
"{ grant role membership#1000117:First.guest to role partner#10001:First.tenant by system and assume }",
"{ grant role membership#1000117:First.guest to role debitor#1000111:First.tenant by system and assume }",

View File

@ -21,7 +21,7 @@ import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipType;
import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity;
import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.test.JpaAttempt;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
@ -520,7 +520,7 @@ public class ImportOfficeData extends ContextBasedTest {
}
private void persist(final Integer id, final HasUuid entity) {
private void persist(final Integer id, final RbacObject entity) {
try {
//System.out.println("persisting #" + entity.hashCode() + ": " + entity);
em.persist(entity);
@ -591,7 +591,7 @@ public class ImportOfficeData extends ContextBasedTest {
}).assertSuccessful();
}
private <E extends HasUuid> void updateLegacyIds(
private <E extends RbacObject> void updateLegacyIds(
Map<Integer, E> entities,
final String legacyIdTable,
final String legacyIdColumn) {

View File

@ -171,29 +171,29 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role person#EBess.admin by system and assume }",
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.owner to role person#HostsharingeG.admin by system and assume }",
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role person#HostsharingeG.admin by system and assume }",
"{ grant perm edit on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
"{ grant perm UPDATE on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.tenant to role relationship#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
"{ grant perm * on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.owner by system and assume }",
"{ grant perm DELETE on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.owner by system and assume }",
"{ grant role relationship#HostsharingeG-with-PARTNER-EBess.admin to role relationship#HostsharingeG-with-PARTNER-EBess.owner by system and assume }",
"{ grant perm view on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
"{ grant perm SELECT on relationship#HostsharingeG-with-PARTNER-EBess to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
"{ grant role contact#4th.tenant to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
"{ grant role person#EBess.tenant to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
"{ grant role person#HostsharingeG.tenant to role relationship#HostsharingeG-with-PARTNER-EBess.tenant by system and assume }",
// owner
"{ grant perm * on partner#20032:EBess-4th to role partner#20032:EBess-4th.owner by system and assume }",
"{ grant perm * on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.owner by system and assume }",
"{ grant perm DELETE on partner#20032:EBess-4th to role partner#20032:EBess-4th.owner by system and assume }",
"{ grant perm DELETE on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.owner by system and assume }",
"{ grant role partner#20032:EBess-4th.owner to role global#global.admin by system and assume }",
// admin
"{ grant perm edit on partner#20032:EBess-4th to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant perm edit on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant perm UPDATE on partner#20032:EBess-4th to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant perm UPDATE on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant role partner#20032:EBess-4th.admin to role partner#20032:EBess-4th.owner by system and assume }",
"{ grant role person#EBess.tenant to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant role contact#4th.tenant to role partner#20032:EBess-4th.admin by system and assume }",
// agent
"{ grant perm view on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.agent by system and assume }",
"{ grant perm SELECT on partner_details#20032:EBess-4th-details to role partner#20032:EBess-4th.agent by system and assume }",
"{ grant role partner#20032:EBess-4th.agent to role partner#20032:EBess-4th.admin by system and assume }",
"{ grant role partner#20032:EBess-4th.agent to role person#EBess.admin by system and assume }",
"{ grant role partner#20032:EBess-4th.agent to role contact#4th.admin by system and assume }",
@ -204,7 +204,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
"{ grant role contact#4th.guest to role partner#20032:EBess-4th.tenant by system and assume }",
// guest
"{ grant perm view on partner#20032:EBess-4th to role partner#20032:EBess-4th.guest by system and assume }",
"{ grant perm SELECT on partner#20032:EBess-4th to role partner#20032:EBess-4th.guest by system and assume }",
"{ grant role partner#20032:EBess-4th.guest to role partner#20032:EBess-4th.tenant by system and assume }",
null)));
@ -473,7 +473,6 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
.contact(givenContact)
.build();
relationshipRepo.save(partnerRole);
em.flush(); // TODO: why is that necessary?
final var newPartner = HsOfficePartnerEntity.builder()
.partnerNumber(partnerNumber)

View File

@ -113,11 +113,11 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTestWithCleanu
Array.from(
initialGrantNames,
"{ grant role hs_office_person#anothernewperson.owner to role global#global.admin by system and assume }",
"{ grant perm edit on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.admin by system and assume }",
"{ grant perm UPDATE on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.admin by system and assume }",
"{ grant role hs_office_person#anothernewperson.tenant to role hs_office_person#anothernewperson.admin by system and assume }",
"{ grant perm * on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.owner by system and assume }",
"{ grant perm DELETE on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.owner by system and assume }",
"{ grant role hs_office_person#anothernewperson.admin to role hs_office_person#anothernewperson.owner by system and assume }",
"{ grant perm view on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.guest by system and assume }",
"{ grant perm SELECT on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.guest by system and assume }",
"{ grant role hs_office_person#anothernewperson.guest to role hs_office_person#anothernewperson.tenant by system and assume }",
"{ grant role hs_office_person#anothernewperson.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }"
));

View File

@ -115,14 +115,14 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
"{ grant perm * on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner by system and assume }",
"{ grant perm DELETE on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner to role global#global.admin by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner to role hs_office_person#BesslerAnita.admin by system and assume }",
"{ grant perm edit on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.admin by system and assume }",
"{ grant perm UPDATE on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.admin by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.admin to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner by system and assume }",
"{ grant perm view on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant by system and assume }",
"{ grant perm SELECT on hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant to role hs_office_contact#fourthcontact.admin by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant to role hs_office_person#BesslerAnita.admin by system and assume }",

View File

@ -131,11 +131,11 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTestWithC
initialGrantNames,
// owner
"{ grant perm * on sepamandate#temprefB to role sepamandate#temprefB.owner by system and assume }",
"{ grant perm DELETE on sepamandate#temprefB to role sepamandate#temprefB.owner by system and assume }",
"{ grant role sepamandate#temprefB.owner to role global#global.admin by system and assume }",
// admin
"{ grant perm edit on sepamandate#temprefB to role sepamandate#temprefB.admin by system and assume }",
"{ grant perm UPDATE on sepamandate#temprefB to role sepamandate#temprefB.admin by system and assume }",
"{ grant role sepamandate#temprefB.admin to role sepamandate#temprefB.owner by system and assume }",
"{ grant role bankaccount#Paul....tenant to role sepamandate#temprefB.admin by system and assume }",
@ -151,7 +151,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTestWithC
"{ grant role bankaccount#Paul....guest to role sepamandate#temprefB.tenant by system and assume }",
// guest
"{ grant perm view on sepamandate#temprefB to role sepamandate#temprefB.guest by system and assume }",
"{ grant perm SELECT on sepamandate#temprefB to role sepamandate#temprefB.guest by system and assume }",
"{ grant role sepamandate#temprefB.guest to role sepamandate#temprefB.tenant by system and assume }",
null));
}

View File

@ -4,6 +4,7 @@ import net.hostsharing.hsadminng.context.ContextBasedTest;
import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantEntity;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantRepository;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleEntity;
import net.hostsharing.hsadminng.rbac.rbacrole.RbacRoleRepository;
import net.hostsharing.test.JpaAttempt;
@ -43,7 +44,7 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
@Autowired
JpaAttempt jpaAttempt;
private TreeMap<UUID, Class<? extends HasUuid>> entitiesToCleanup = new TreeMap<>();
private TreeMap<UUID, Class<? extends RbacObject>> entitiesToCleanup = new TreeMap<>();
private static Long latestIntialTestDataSerialId;
private static boolean countersInitialized = false;
@ -61,7 +62,7 @@ public abstract class ContextBasedTestWithCleanup extends ContextBasedTest {
return uuidToCleanup;
}
public <E extends HasUuid> E toCleanup(final E entity) {
public <E extends RbacObject> E toCleanup(final E entity) {
out.println("toCleanup(" + entity.getClass() + ", " + entity.getUuid());
if ( entity.getUuid() == null ) {
throw new IllegalArgumentException("only persisted entities with valid uuid allowed");

View File

@ -1,67 +0,0 @@
package net.hostsharing.hsadminng.rbac.rbacgrant;
import lombok.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.annotation.Immutable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.List;
import java.util.UUID;
@Entity
@Table(name = "rbacgrants_ev")
@Getter
@Setter
@Builder
@ToString
@Immutable
@NoArgsConstructor
@AllArgsConstructor
public class RawRbacGrantEntity {
@Id
private UUID uuid;
@Column(name = "grantedbyroleidname", updatable = false, insertable = false)
private String grantedByRoleIdName;
@Column(name = "grantedbyroleuuid", updatable = false, insertable = false)
private UUID grantedByRoleUuid;
@Column(name = "ascendantidname", updatable = false, insertable = false)
private String ascendantIdName;
@Column(name = "ascendantuuid", updatable = false, insertable = false)
private UUID ascendingUuid;
@Column(name = "descendantidname", updatable = false, insertable = false)
private String descendantIdName;
@Column(name = "descendantuuid", updatable = false, insertable = false)
private UUID descendantUuid;
@Column(name = "assumed", updatable = false, insertable = false)
private boolean assumed;
public String toDisplay() {
// @formatter:off
return "{ grant " + descendantIdName +
" to " + ascendantIdName +
" by " + ( grantedByRoleUuid == null
? "system"
: grantedByRoleIdName ) +
( assumed ? " and assume" : "") +
" }";
// @formatter:on
}
@NotNull
public static List<String> distinctGrantDisplaysOf(final List<RawRbacGrantEntity> roles) {
// TODO: remove .distinct() once partner.person + partner.contact are removed
return roles.stream().map(RawRbacGrantEntity::toDisplay).sorted().distinct().toList();
}
}

View File

@ -1,11 +0,0 @@
package net.hostsharing.hsadminng.rbac.rbacgrant;
import org.springframework.data.repository.Repository;
import java.util.List;
import java.util.UUID;
public interface RawRbacGrantRepository extends Repository<RawRbacGrantEntity, UUID> {
List<RawRbacGrantEntity> findAll();
}

View File

@ -73,14 +73,16 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
.contentType("application/json")
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "global#global.admin"),
// TODO: should there be a grantedByRole or just a grantedByTrigger?
hasEntry("grantedByRoleIdName", "test_customer#xxx.owner"),
hasEntry("grantedRoleIdName", "test_customer#xxx.admin"),
hasEntry("granteeUserName", "customer-admin@xxx.example.com")
)
))
.body("", hasItem(
allOf(
hasEntry("grantedByRoleIdName", "global#global.admin"),
// TODO: should there be a grantedByRole or just a grantedByTrigger?
hasEntry("grantedByRoleIdName", "test_customer#yyy.owner"),
hasEntry("grantedRoleIdName", "test_customer#yyy.admin"),
hasEntry("granteeUserName", "customer-admin@yyy.example.com")
)
@ -296,7 +298,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
result.assertThat()
.statusCode(403)
.body("message", containsString("Access to granted role"))
.body("message", containsString("forbidden for {test_package#xxx00.admin}"));
.body("message", containsString("forbidden for test_package#xxx00.admin"));
assertThat(findAllGrantsOf(givenCurrentUserAsPackageAdmin))
.extracting(RbacGrantEntity::getGranteeUserName)
.doesNotContain(givenNewUser.getName());

View File

@ -84,7 +84,7 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// then
exactlyTheseRbacGrantsAreReturned(
result,
"{ grant role test_customer#xxx.admin to user customer-admin@xxx.example.com by role global#global.admin and assume }",
"{ grant role test_customer#xxx.admin to user customer-admin@xxx.example.com by role test_customer#xxx.owner and assume }",
"{ grant role test_package#xxx00.admin to user pac-admin-xxx00@xxx.example.com by role test_customer#xxx.admin and assume }",
"{ grant role test_package#xxx01.admin to user pac-admin-xxx01@xxx.example.com by role test_customer#xxx.admin and assume }",
"{ grant role test_package#xxx02.admin to user pac-admin-xxx02@xxx.example.com by role test_customer#xxx.admin and assume }");
@ -162,8 +162,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// then
attempt.assertExceptionWithRootCauseMessage(
JpaSystemException.class,
"ERROR: [403] Access to granted role " + given.packageOwnerRoleUuid
+ " forbidden for {test_package#xxx00.admin}");
"ERROR: [403] Access to granted role test_package#xxx00.owner",
"forbidden for test_package#xxx00.admin");
jpaAttempt.transacted(() -> {
// finally, we use the new user to make sure, no roles were granted
context(given.arbitraryUser.getName(), null);

View File

@ -0,0 +1,103 @@
package net.hostsharing.hsadminng.rbac.rbacgrant;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService.Include;
import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.EnumSet;
import java.util.UUID;
import static java.lang.String.join;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class, RbacGrantsDiagramService.class})
class RbacGrantsDiagramServiceIntegrationTest extends ContextBasedTestWithCleanup {
@Autowired
RbacGrantsDiagramService grantsMermaidService;
@MockBean
HttpServletRequest request;
@Autowired
Context context;
@Autowired
RbacGrantsDiagramService diagramService;
TestInfo test;
@BeforeEach
void init(TestInfo testInfo) {
this.test = testInfo;
}
protected void context(final String currentUser, final String assumedRoles) {
context.define(test.getDisplayName(), null, currentUser, assumedRoles);
}
protected void context(final String currentUser) {
context(currentUser, null);
}
@Test
void allGrantsToCurrentUser() {
context("superuser-alex@hostsharing.net", "test_domain#xxx00-aaaa.owner");
final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.TEST_ENTITIES));
assertThat(graph).isEqualTo("""
flowchart TB
role:test_domain#xxx00-aaaa.admin --> role:test_package#xxx00.tenant
role:test_domain#xxx00-aaaa.owner --> role:test_domain#xxx00-aaaa.admin
role:test_domain#xxx00-aaaa.owner --> role:test_package#xxx00.tenant
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant
""".trim());
}
@Test
void allGrantsToCurrentUserIncludingPermissions() {
context("superuser-alex@hostsharing.net", "test_domain#xxx00-aaaa.owner");
final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.TEST_ENTITIES, Include.PERMISSIONS));
assertThat(graph).isEqualTo("""
flowchart TB
role:test_customer#xxx.tenant --> perm:SELECT:on:test_customer#xxx
role:test_domain#xxx00-aaaa.admin --> perm:SELECT:on:test_domain#xxx00-aaaa
role:test_domain#xxx00-aaaa.admin --> role:test_package#xxx00.tenant
role:test_domain#xxx00-aaaa.owner --> perm:DELETE:on:test_domain#xxx00-aaaa
role:test_domain#xxx00-aaaa.owner --> perm:UPDATE:on:test_domain#xxx00-aaaa
role:test_domain#xxx00-aaaa.owner --> role:test_domain#xxx00-aaaa.admin
role:test_domain#xxx00-aaaa.owner --> role:test_package#xxx00.tenant
role:test_package#xxx00.tenant --> perm:SELECT:on:test_package#xxx00
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant
""".trim());
}
@Test
@Disabled // enable to generate from a real database
void print() throws IOException {
//context("superuser-alex@hostsharing.net", "hs_office_person#FirbySusan.admin");
context("superuser-alex@hostsharing.net");
//final var graph = grantsMermaidService.allGrantsToCurrentUser(EnumSet.of(Include.NON_TEST_ENTITIES, Include.PERMISSIONS));
final var targetObject = (UUID) em.createNativeQuery("SELECT uuid FROM hs_office_coopassetstransaction WHERE reference='ref 1000101-1'").getSingleResult();
final var graph = grantsMermaidService.allGrantsFrom(targetObject, "view", EnumSet.of(Include.USERS));
RbacGrantsDiagramService.writeToFile(join(";", context.getAssumedRoles()), graph, "doc/all-grants.md");
}
}

View File

@ -0,0 +1,31 @@
package net.hostsharing.hsadminng.rbac.rbacrole;
import lombok.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.annotation.Immutable;
import jakarta.persistence.*;
import java.util.List;
import java.util.UUID;
@Entity
@Table(name = "rbacobject") // TODO: create view rbacobject_ev
@Getter
@Setter
@ToString
@Immutable
@NoArgsConstructor
@AllArgsConstructor
public class RawRbacObjectEntity {
@Id
private UUID uuid;
@Column(name="objecttable")
private String objectTable;
@NotNull
public static List<String> objectDisplaysOf(@NotNull final List<RawRbacObjectEntity> roles) {
return roles.stream().map(e -> e.objectTable+ "#" + e.uuid).sorted().toList();
}
}

View File

@ -0,0 +1,11 @@
package net.hostsharing.hsadminng.rbac.rbacrole;
import org.springframework.data.repository.Repository;
import java.util.List;
import java.util.UUID;
public interface RawRbacObjectRepository extends Repository<RawRbacObjectEntity, UUID> {
List<RawRbacObjectEntity> findAll();
}

View File

@ -288,19 +288,15 @@ class RbacUserControllerAcceptanceTest {
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy.tenant"),
hasEntry("op", "view"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_package#yyy00.admin"),
hasEntry("op", "add-domain"))
hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
hasEntry("op", "*"))
hasEntry("op", "DELETE"))
))
.body("size()", is(7));
// actual content tested in integration test, so this is enough for here:
.body("size()", greaterThanOrEqualTo(6));
// @formatter:on
}
@ -313,7 +309,7 @@ class RbacUserControllerAcceptanceTest {
RestAssured
.given()
.header("current-user", "superuser-alex@hostsharing.net")
.header("assumed-roles", "test_package#yyy00.admin")
.header("assumed-roles", "test_customer#yyy.admin")
.port(port)
.when()
.get("http://localhost/api/rbac/users/" + givenUser.getUuid() + "/permissions")
@ -323,19 +319,15 @@ class RbacUserControllerAcceptanceTest {
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy.tenant"),
hasEntry("op", "view"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_package#yyy00.admin"),
hasEntry("op", "add-domain"))
hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
hasEntry("op", "*"))
hasEntry("op", "DELETE"))
))
.body("size()", is(7));
// actual content tested in integration test, so this is enough for here:
.body("size()", greaterThanOrEqualTo(6));
// @formatter:on
}
@ -357,19 +349,15 @@ class RbacUserControllerAcceptanceTest {
.body("", hasItem(
allOf(
hasEntry("roleName", "test_customer#yyy.tenant"),
hasEntry("op", "view"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_package#yyy00.admin"),
hasEntry("op", "add-domain"))
hasEntry("op", "SELECT"))
))
.body("", hasItem(
allOf(
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
hasEntry("op", "*"))
hasEntry("op", "DELETE"))
))
.body("size()", is(7));
// actual content tested in integration test, so this is enough for here:
.body("size()", greaterThanOrEqualTo(6));
// @formatter:on
}

View File

@ -20,6 +20,7 @@ import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.UUID;
import static java.util.Comparator.comparing;
import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat;
@ -181,50 +182,48 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
private static final String[] ALL_USER_PERMISSIONS = Array.of(
// @formatter:off
"global#global.admin -> global#global: add-customer",
"test_customer#xxx.admin -> test_customer#xxx: SELECT",
"test_customer#xxx.owner -> test_customer#xxx: DELETE",
"test_customer#xxx.tenant -> test_customer#xxx: SELECT",
"test_customer#xxx.admin -> test_customer#xxx: INSERT:test_package",
"test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
"test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
"test_package#xxx00.tenant -> test_package#xxx00: SELECT",
"test_package#xxx01.admin -> test_package#xxx01: INSERT:test_domain",
"test_package#xxx01.admin -> test_package#xxx01: INSERT:test_domain",
"test_package#xxx01.tenant -> test_package#xxx01: SELECT",
"test_package#xxx02.admin -> test_package#xxx02: INSERT:test_domain",
"test_package#xxx02.admin -> test_package#xxx02: INSERT:test_domain",
"test_package#xxx02.tenant -> test_package#xxx02: SELECT",
"test_customer#xxx.admin -> test_customer#xxx: add-package",
"test_customer#xxx.admin -> test_customer#xxx: view",
"test_customer#xxx.owner -> test_customer#xxx: *",
"test_customer#xxx.tenant -> test_customer#xxx: view",
"test_package#xxx00.admin -> test_package#xxx00: add-domain",
"test_package#xxx00.admin -> test_package#xxx00: add-domain",
"test_package#xxx00.tenant -> test_package#xxx00: view",
"test_package#xxx01.admin -> test_package#xxx01: add-domain",
"test_package#xxx01.admin -> test_package#xxx01: add-domain",
"test_package#xxx01.tenant -> test_package#xxx01: view",
"test_package#xxx02.admin -> test_package#xxx02: add-domain",
"test_package#xxx02.admin -> test_package#xxx02: add-domain",
"test_package#xxx02.tenant -> test_package#xxx02: view",
"test_customer#yyy.admin -> test_customer#yyy: SELECT",
"test_customer#yyy.owner -> test_customer#yyy: DELETE",
"test_customer#yyy.tenant -> test_customer#yyy: SELECT",
"test_customer#yyy.admin -> test_customer#yyy: INSERT:test_package",
"test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
"test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
"test_package#yyy00.tenant -> test_package#yyy00: SELECT",
"test_package#yyy01.admin -> test_package#yyy01: INSERT:test_domain",
"test_package#yyy01.admin -> test_package#yyy01: INSERT:test_domain",
"test_package#yyy01.tenant -> test_package#yyy01: SELECT",
"test_package#yyy02.admin -> test_package#yyy02: INSERT:test_domain",
"test_package#yyy02.admin -> test_package#yyy02: INSERT:test_domain",
"test_package#yyy02.tenant -> test_package#yyy02: SELECT",
"test_customer#yyy.admin -> test_customer#yyy: add-package",
"test_customer#yyy.admin -> test_customer#yyy: view",
"test_customer#yyy.owner -> test_customer#yyy: *",
"test_customer#yyy.tenant -> test_customer#yyy: view",
"test_package#yyy00.admin -> test_package#yyy00: add-domain",
"test_package#yyy00.admin -> test_package#yyy00: add-domain",
"test_package#yyy00.tenant -> test_package#yyy00: view",
"test_package#yyy01.admin -> test_package#yyy01: add-domain",
"test_package#yyy01.admin -> test_package#yyy01: add-domain",
"test_package#yyy01.tenant -> test_package#yyy01: view",
"test_package#yyy02.admin -> test_package#yyy02: add-domain",
"test_package#yyy02.admin -> test_package#yyy02: add-domain",
"test_package#yyy02.tenant -> test_package#yyy02: view",
"test_customer#zzz.admin -> test_customer#zzz: add-package",
"test_customer#zzz.admin -> test_customer#zzz: view",
"test_customer#zzz.owner -> test_customer#zzz: *",
"test_customer#zzz.tenant -> test_customer#zzz: view",
"test_package#zzz00.admin -> test_package#zzz00: add-domain",
"test_package#zzz00.admin -> test_package#zzz00: add-domain",
"test_package#zzz00.tenant -> test_package#zzz00: view",
"test_package#zzz01.admin -> test_package#zzz01: add-domain",
"test_package#zzz01.admin -> test_package#zzz01: add-domain",
"test_package#zzz01.tenant -> test_package#zzz01: view",
"test_package#zzz02.admin -> test_package#zzz02: add-domain",
"test_package#zzz02.admin -> test_package#zzz02: add-domain",
"test_package#zzz02.tenant -> test_package#zzz02: view"
// @formatter:on
"test_customer#zzz.admin -> test_customer#zzz: SELECT",
"test_customer#zzz.owner -> test_customer#zzz: DELETE",
"test_customer#zzz.tenant -> test_customer#zzz: SELECT",
"test_customer#zzz.admin -> test_customer#zzz: INSERT:test_package",
"test_package#zzz00.admin -> test_package#zzz00: INSERT:test_domain",
"test_package#zzz00.admin -> test_package#zzz00: INSERT:test_domain",
"test_package#zzz00.tenant -> test_package#zzz00: SELECT",
"test_package#zzz01.admin -> test_package#zzz01: INSERT:test_domain",
"test_package#zzz01.admin -> test_package#zzz01: INSERT:test_domain",
"test_package#zzz01.tenant -> test_package#zzz01: SELECT",
"test_package#zzz02.admin -> test_package#zzz02: INSERT:test_domain",
"test_package#zzz02.admin -> test_package#zzz02: INSERT:test_domain",
"test_package#zzz02.tenant -> test_package#zzz02: SELECT"
// @formatter:on
);
@Test
@ -233,7 +232,9 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("superuser-alex@hostsharing.net");
// when
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("superuser-alex@hostsharing.net"));
final var result = rbacUserRepository.findPermissionsOfUserByUuid(userUUID("superuser-fran@hostsharing.net"))
.stream().filter(p -> p.getObjectTable().contains("test_"))
.sorted(comparing(RbacUserPermission::toString)).toList();
// then
allTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS);
@ -251,32 +252,32 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"test_customer#xxx.admin -> test_customer#xxx: add-package",
"test_customer#xxx.admin -> test_customer#xxx: view",
"test_customer#xxx.tenant -> test_customer#xxx: view",
"test_customer#xxx.admin -> test_customer#xxx: INSERT:test_package",
"test_customer#xxx.admin -> test_customer#xxx: SELECT",
"test_customer#xxx.tenant -> test_customer#xxx: SELECT",
"test_package#xxx00.admin -> test_package#xxx00: add-domain",
"test_package#xxx00.admin -> test_package#xxx00: add-domain",
"test_package#xxx00.tenant -> test_package#xxx00: view",
"test_domain#xxx00-aaaa.owner -> test_domain#xxx00-aaaa: *",
"test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
"test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
"test_package#xxx00.tenant -> test_package#xxx00: SELECT",
"test_domain#xxx00-aaaa.owner -> test_domain#xxx00-aaaa: DELETE",
"test_package#xxx01.admin -> test_package#xxx01: add-domain",
"test_package#xxx01.admin -> test_package#xxx01: add-domain",
"test_package#xxx01.tenant -> test_package#xxx01: view",
"test_domain#xxx01-aaaa.owner -> test_domain#xxx01-aaaa: *",
"test_package#xxx01.admin -> test_package#xxx01: INSERT:test_domain",
"test_package#xxx01.admin -> test_package#xxx01: INSERT:test_domain",
"test_package#xxx01.tenant -> test_package#xxx01: SELECT",
"test_domain#xxx01-aaaa.owner -> test_domain#xxx01-aaaa: DELETE",
"test_package#xxx02.admin -> test_package#xxx02: add-domain",
"test_package#xxx02.admin -> test_package#xxx02: add-domain",
"test_package#xxx02.tenant -> test_package#xxx02: view",
"test_domain#xxx02-aaaa.owner -> test_domain#xxx02-aaaa: *"
"test_package#xxx02.admin -> test_package#xxx02: INSERT:test_domain",
"test_package#xxx02.admin -> test_package#xxx02: INSERT:test_domain",
"test_package#xxx02.tenant -> test_package#xxx02: SELECT",
"test_domain#xxx02-aaaa.owner -> test_domain#xxx02-aaaa: DELETE"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"test_customer#yyy.admin -> test_customer#yyy: add-package",
"test_customer#yyy.admin -> test_customer#yyy: view",
"test_customer#yyy.tenant -> test_customer#yyy: view"
"test_customer#yyy.admin -> test_customer#yyy: INSERT:test_package",
"test_customer#yyy.admin -> test_customer#yyy: SELECT",
"test_customer#yyy.tenant -> test_customer#yyy: SELECT"
// @formatter:on
);
}
@ -311,26 +312,26 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"test_customer#xxx.tenant -> test_customer#xxx: view",
"test_customer#xxx.tenant -> test_customer#xxx: SELECT",
// "test_customer#xxx.admin -> test_customer#xxx: view" - Not permissions through the customer admin!
"test_package#xxx00.admin -> test_package#xxx00: add-domain",
"test_package#xxx00.admin -> test_package#xxx00: add-domain",
"test_package#xxx00.tenant -> test_package#xxx00: view",
"test_domain#xxx00-aaaa.owner -> test_domain#xxx00-aaaa: *",
"test_domain#xxx00-aaab.owner -> test_domain#xxx00-aaab: *"
"test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
"test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
"test_package#xxx00.tenant -> test_package#xxx00: SELECT",
"test_domain#xxx00-aaaa.owner -> test_domain#xxx00-aaaa: DELETE",
"test_domain#xxx00-aaab.owner -> test_domain#xxx00-aaab: DELETE"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"test_customer#yyy.admin -> test_customer#yyy: add-package",
"test_customer#yyy.admin -> test_customer#yyy: view",
"test_customer#yyy.tenant -> test_customer#yyy: view",
"test_package#yyy00.admin -> test_package#yyy00: add-domain",
"test_package#yyy00.admin -> test_package#yyy00: add-domain",
"test_package#yyy00.tenant -> test_package#yyy00: view",
"test_domain#yyy00-aaaa.owner -> test_domain#yyy00-aaaa: *",
"test_domain#yyy00-aaab.owner -> test_domain#yyy00-aaab: *"
"test_customer#yyy.admin -> test_customer#yyy: INSERT:test_package",
"test_customer#yyy.admin -> test_customer#yyy: SELECT",
"test_customer#yyy.tenant -> test_customer#yyy: SELECT",
"test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
"test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
"test_package#yyy00.tenant -> test_package#yyy00: SELECT",
"test_domain#yyy00-aaaa.owner -> test_domain#yyy00-aaaa: DELETE",
"test_domain#yyy00-aaab.owner -> test_domain#yyy00-aaab: DELETE"
// @formatter:on
);
}
@ -359,11 +360,10 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
allTheseRbacPermissionsAreReturned(
result,
// @formatter:off
"test_customer#xxx.tenant -> test_customer#xxx: view",
"test_customer#xxx.tenant -> test_customer#xxx: SELECT",
// "test_customer#xxx.admin -> test_customer#xxx: view" - Not permissions through the customer admin!
"test_package#xxx00.admin -> test_package#xxx00: add-domain",
"test_package#xxx00.admin -> test_package#xxx00: add-domain",
"test_package#xxx00.tenant -> test_package#xxx00: view"
"test_package#xxx00.admin -> test_package#xxx00: INSERT:test_domain",
"test_package#xxx00.tenant -> test_package#xxx00: SELECT"
// @formatter:on
);
noneOfTheseRbacPermissionsAreReturned(
@ -373,13 +373,13 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
"test_customer#xxx.admin -> test_customer#xxx: add-package",
// no permissions on other customer's objects
"test_customer#yyy.admin -> test_customer#yyy: add-package",
"test_customer#yyy.admin -> test_customer#yyy: view",
"test_customer#yyy.tenant -> test_customer#yyy: view",
"test_package#yyy00.admin -> test_package#yyy00: add-domain",
"test_package#yyy00.admin -> test_package#yyy00: add-domain",
"test_package#yyy00.tenant -> test_package#yyy00: view",
"test_domain#yyy00-aaaa.owner -> test_domain#yyy00-aaaa: *",
"test_domain#yyy00-xxxb.owner -> test_domain#yyy00-xxxb: *"
"test_customer#yyy.admin -> test_customer#yyy: SELECT",
"test_customer#yyy.tenant -> test_customer#yyy: SELECT",
"test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
"test_package#yyy00.admin -> test_package#yyy00: INSERT:test_domain",
"test_package#yyy00.tenant -> test_package#yyy00: SELECT",
"test_domain#yyy00-aaaa.owner -> test_domain#yyy00-aaaa: DELETE",
"test_domain#yyy00-xxxb.owner -> test_domain#yyy00-xxxb: DELETE"
// @formatter:on
);
}
@ -432,7 +432,8 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
final List<RbacUserPermission> actualResult,
final String... expectedRoleNames) {
assertThat(actualResult)
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp())
.extracting(p -> p.getRoleName() + " -> " + p.getObjectTable() + "#" + p.getObjectIdName() + ": " + p.getOp()
+ (p.getOpTableName() != null ? (":"+p.getOpTableName()) : "" ))
.contains(expectedRoleNames);
}

View File

@ -148,7 +148,7 @@ class TestCustomerControllerAcceptanceTest {
// finally, the new customer can be viewed by its own admin
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
context.define("customer-admin@uuu.example.com");
context.define("superuser-fran@hostsharing.net", "test_customer#uuu.admin");
assertThat(testCustomerRepository.findByUuid(newUserUuid))
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("uuu"));
}
@ -175,7 +175,7 @@ class TestCustomerControllerAcceptanceTest {
.statusCode(403)
.contentType(ContentType.JSON)
.statusCode(403)
.body("message", containsString("add-customer not permitted for test_customer#xxx.admin"));
.body("message", containsString("insert into test_customer not allowed for current subjects {test_customer#xxx.admin}"));
// @formatter:on
// finally, the new customer was not created
@ -204,7 +204,7 @@ class TestCustomerControllerAcceptanceTest {
.statusCode(403)
.contentType(ContentType.JSON)
.statusCode(403)
.body("message", containsString("add-customer not permitted for customer-admin@yyy.example.com"));
.body("message", containsString("insert into test_customer not allowed for current subjects {customer-admin@yyy.example.com}"));
// @formatter:on
// finally, the new customer was not created

View File

@ -0,0 +1,52 @@
package net.hostsharing.hsadminng.test.cust;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacViewMermaidFlowchartGenerator;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class TestCustomerEntityUnitTest {
@Test
void definesRbac() {
final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(TestCustomerEntity.rbac()).toString();
assertThat(rbacFlowchart).isEqualTo("""
%%{init:{'flowchart':{'htmlLabels':false}}}%%
flowchart TB
subgraph customer["`**customer**`"]
direction TB
style customer fill:#dd4901,stroke:#274d6e,stroke-width:8px
subgraph customer:roles[ ]
style customer:roles fill:#dd4901,stroke:white
role:customer:owner[[customer:owner]]
role:customer:admin[[customer:admin]]
role:customer:tenant[[customer:tenant]]
end
subgraph customer:permissions[ ]
style customer:permissions fill:#dd4901,stroke:white
perm:customer:DELETE{{customer:DELETE}}
perm:customer:UPDATE{{customer:UPDATE}}
perm:customer:SELECT{{customer:SELECT}}
end
end
%% granting roles to users
user:creator ==>|XX| role:customer:owner
%% granting roles to roles
role:global:admin ==>|XX| role:customer:owner
role:customer:owner ==> role:customer:admin
role:customer:admin ==> role:customer:tenant
%% granting permissions to roles
role:customer:owner ==> perm:customer:DELETE
role:customer:admin ==> perm:customer:UPDATE
role:customer:tenant ==> perm:customer:SELECT
""");
}
}

View File

@ -10,8 +10,6 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.PersistenceException;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
@ -27,9 +25,6 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
TestCustomerRepository testCustomerRepository;
@PersistenceContext
EntityManager em;
@MockBean
HttpServletRequest request;
@ -43,7 +38,6 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
final var count = testCustomerRepository.count();
// when
final var result = attempt(em, () -> {
final var newCustomer = new TestCustomerEntity(
UUID.randomUUID(), "www", 90001, "customer-admin@www.example.com");
@ -72,7 +66,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
"add-customer not permitted for test_customer#xxx.admin");
"ERROR: [403] insert into test_customer not allowed for current subjects {test_customer#xxx.admin}");
}
@Test
@ -90,7 +84,7 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
// then
result.assertExceptionWithRootCauseMessage(
PersistenceException.class,
"add-customer not permitted for customer-admin@xxx.example.com");
"ERROR: [403] insert into test_customer not allowed for current subjects {customer-admin@xxx.example.com}");
}
@ -116,15 +110,15 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
}
@Test
public void globalAdmin_withAssumedglobalAdminRole_canViewAllCustomers() {
public void globalAdmin_withAssumedCustomerOwnerRole_canViewExactlyThatCustomer() {
given:
context("superuser-alex@hostsharing.net", "global#global.admin");
context("superuser-alex@hostsharing.net", "test_customer#yyy.owner");
// when
final var result = testCustomerRepository.findCustomerByOptionalPrefixLike(null);
then:
allTheseCustomersAreReturned(result, "xxx", "yyy", "zzz");
allTheseCustomersAreReturned(result, "yyy");
}
@Test
@ -141,6 +135,8 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
@Test
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnCustomer() {
context("customer-admin@xxx.example.com");
context("customer-admin@xxx.example.com", "test_package#xxx00.admin");
final var result = testCustomerRepository.findCustomerByOptionalPrefixLike(null);

View File

@ -0,0 +1,68 @@
package net.hostsharing.hsadminng.test.pac;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacViewMermaidFlowchartGenerator;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class TestPackageEntityUnitTest {
@Test
void definesRbac() {
final var rbacFlowchart = new RbacViewMermaidFlowchartGenerator(TestPackageEntity.rbac()).toString();
assertThat(rbacFlowchart).isEqualTo("""
%%{init:{'flowchart':{'htmlLabels':false}}}%%
flowchart TB
subgraph package["`**package**`"]
direction TB
style package fill:#dd4901,stroke:#274d6e,stroke-width:8px
subgraph package:roles[ ]
style package:roles fill:#dd4901,stroke:white
role:package:owner[[package:owner]]
role:package:admin[[package:admin]]
role:package:tenant[[package:tenant]]
end
subgraph package:permissions[ ]
style package:permissions fill:#dd4901,stroke:white
perm:package:INSERT{{package:INSERT}}
perm:package:DELETE{{package:DELETE}}
perm:package:UPDATE{{package:UPDATE}}
perm:package:SELECT{{package:SELECT}}
end
end
subgraph customer["`**customer**`"]
direction TB
style customer fill:#99bcdb,stroke:#274d6e,stroke-width:8px
subgraph customer:roles[ ]
style customer:roles fill:#99bcdb,stroke:white
role:customer:owner[[customer:owner]]
role:customer:admin[[customer:admin]]
role:customer:tenant[[customer:tenant]]
end
end
%% granting roles to roles
role:global:admin -.->|XX| role:customer:owner
role:customer:owner -.-> role:customer:admin
role:customer:admin -.-> role:customer:tenant
role:customer:admin ==> role:package:owner
role:package:owner ==> role:package:admin
role:package:admin ==> role:package:tenant
role:package:tenant ==> role:customer:tenant
%% granting permissions to roles
role:customer:admin ==> perm:package:INSERT
role:package:owner ==> perm:package:DELETE
role:package:owner ==> perm:package:UPDATE
role:package:tenant ==> perm:package:SELECT
""");
}
}

View File

@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.test.pac;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.context.ContextBasedTest;
import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@ -19,10 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
class TestPackageRepositoryIntegrationTest {
@Autowired
Context context;
class TestPackageRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
TestPackageRepository testPackageRepository;
@ -40,9 +38,10 @@ class TestPackageRepositoryIntegrationTest {
class FindAllByOptionalNameLike {
@Test
public void globalAdmin_withoutAssumedRole_canNotViewAnyPackages_becauseThoseGrantsAreNotassumedd() {
public void globalAdmin_withoutAssumedRole_canNotViewAnyPackages_becauseThoseGrantsAreNotAssumed() {
// given
context.define("superuser-alex@hostsharing.net");
// alex is not just global-admin but lso the creating user, thus we use fran
context.define("superuser-fran@hostsharing.net");
// when
final var result = testPackageRepository.findAllByOptionalNameLike(null);
@ -52,7 +51,7 @@ class TestPackageRepositoryIntegrationTest {
}
@Test
public void globalAdmin_withAssumedglobalAdminRole__canNotViewAnyPackages_becauseThoseGrantsAreNotassumedd() {
public void globalAdmin_withAssumedglobalAdminRole__canNotViewAnyPackages_becauseThoseGrantsAreNotAssumed() {
given:
context.define("superuser-alex@hostsharing.net", "global#global.admin");
@ -89,7 +88,7 @@ class TestPackageRepositoryIntegrationTest {
class OptimisticLocking {
@Test
public void supportsOptimisticLocking() throws InterruptedException {
public void supportsOptimisticLocking() {
// given
globalAdminWithAssumedRole("test_package#xxx00.admin");
final var pac = testPackageRepository.findAllByOptionalNameLike("%").get(0);