RBAC Diagram+PostgreSQL Generator #21

Merged
hsh-michaelhoennig merged 54 commits from experimental-rbacview-generator into master 2024-03-11 12:30:44 +01:00
18 changed files with 203 additions and 97 deletions
Showing only changes of commit d40cf019cc - Show all commits

View File

@ -197,7 +197,7 @@ public class RbacView {
}); });
importedRbacView.getGrantDefs().forEach(grantDef -> { importedRbacView.getGrantDefs().forEach(grantDef -> {
if (grantDef.grantType() == RbacGrantDefinition.GrantType.ROLE_TO_ROLE) { if (grantDef.grantType() == RbacGrantDefinition.GrantType.ROLE_TO_ROLE) {
findOrCreateGrantDef( final var importedGrantDef = findOrCreateGrantDef(
findRbacRole( findRbacRole(
mapper.map(grantDef.getSubRoleDef().entityAlias.aliasName), mapper.map(grantDef.getSubRoleDef().entityAlias.aliasName),
grantDef.getSubRoleDef().getRole()), grantDef.getSubRoleDef().getRole()),
@ -205,6 +205,9 @@ public class RbacView {
mapper.map(grantDef.getSuperRoleDef().entityAlias.aliasName), mapper.map(grantDef.getSuperRoleDef().entityAlias.aliasName),
grantDef.getSuperRoleDef().getRole()) grantDef.getSuperRoleDef().getRole())
); );
if (!grantDef.isAssumed()) {
importedGrantDef.unassumed();
}
} }
}); });
return this; return this;

View File

@ -109,9 +109,8 @@ public class RbacViewMermaidFlowchart {
} }
private String grantDef(final RbacView.RbacGrantDefinition grant) { private String grantDef(final RbacView.RbacGrantDefinition grant) {
final var arrow = grant.isToCreate() final var arrow = (grant.isToCreate() ? " ==>" : " -.->")
? grant.isAssumed() ? " ==> " : " == /// ==> " + (grant.isAssumed() ? " " : "|XX| ");
: grant.isAssumed() ? " -.-> " : " -.- /// -.-> ";
return switch (grant.grantType()) { return switch (grant.grantType()) {
case ROLE_TO_USER -> case ROLE_TO_USER ->
// TODO: other user types not implemented yet // TODO: other user types not implemented yet

View File

@ -230,7 +230,8 @@ class RolesGrantsAndPermissionsGenerator {
private String generateGrant(RbacView.RbacGrantDefinition grantDef) { private String generateGrant(RbacView.RbacGrantDefinition grantDef) {
return switch (grantDef.grantType()) { return switch (grantDef.grantType()) {
case ROLE_TO_USER -> throw new IllegalArgumentException("unexpected grant"); case ROLE_TO_USER -> throw new IllegalArgumentException("unexpected grant");
case ROLE_TO_ROLE -> "call grantRoleToRole(${subRoleRef}, ${superRoleRef});" case ROLE_TO_ROLE -> "call grantRoleToRole(${subRoleRef}, ${superRoleRef}${assumed});"
.replace("${assumed}", grantDef.isAssumed() ? "" : ", unassumed()")
.replace("${subRoleRef}", roleRef(NEW, grantDef.getSubRoleDef())) .replace("${subRoleRef}", roleRef(NEW, grantDef.getSubRoleDef()))
.replace("${superRoleRef}", roleRef(NEW, grantDef.getSuperRoleDef())); .replace("${superRoleRef}", roleRef(NEW, grantDef.getSuperRoleDef()));
case PERM_TO_ROLE -> case PERM_TO_ROLE ->
@ -345,12 +346,11 @@ class RolesGrantsAndPermissionsGenerator {
private void generateIncomingSuperRolesForRole(final StringWriter plPgSql, final RbacView.Role role) { private void generateIncomingSuperRolesForRole(final StringWriter plPgSql, final RbacView.Role role) {
final var incomingGrants = findIncomingSuperRolesForRole(rbacDef.getRootEntityAlias(), role); final var incomingGrants = findIncomingSuperRolesForRole(rbacDef.getRootEntityAlias(), role);
if (!incomingGrants.isEmpty()) { if (!incomingGrants.isEmpty()) {
final var arraElements = incomingGrants.stream() final var arrayElements = incomingGrants.stream()
.map(RbacView.RbacGrantDefinition::getSuperRoleDef) .map(g -> toPlPgSqlReference(NEW, g.getSuperRoleDef(), g.isAssumed()))
.map(r -> toPlPgSqlReference(NEW, r))
.toList(); .toList();
plPgSql.indented(() -> plPgSql.indented(() ->
plPgSql.writeLn("incomingSuperRoles => array[" + joinArrayElements(arraElements, 1) + "],\n")); plPgSql.writeLn("incomingSuperRoles => array[" + joinArrayElements(arrayElements, 1) + "],\n"));
rbacGrants.removeAll(incomingGrants); rbacGrants.removeAll(incomingGrants);
} }
} }
@ -359,8 +359,7 @@ class RolesGrantsAndPermissionsGenerator {
final var outgoingGrants = findOutgoingSuperRolesForRole(rbacDef.getRootEntityAlias(), role); final var outgoingGrants = findOutgoingSuperRolesForRole(rbacDef.getRootEntityAlias(), role);
if (!outgoingGrants.isEmpty()) { if (!outgoingGrants.isEmpty()) {
final var arrayElements = outgoingGrants.stream() final var arrayElements = outgoingGrants.stream()
.map(RbacView.RbacGrantDefinition::getSubRoleDef) .map(g -> toPlPgSqlReference(NEW, g.getSubRoleDef(), g.isAssumed()))
.map(r -> toPlPgSqlReference(NEW, r))
.toList(); .toList();
plPgSql.indented(() -> plPgSql.indented(() ->
plPgSql.writeLn("outgoingSubRoles => array[" + joinArrayElements(arrayElements, 1) + "],\n")); plPgSql.writeLn("outgoingSubRoles => array[" + joinArrayElements(arrayElements, 1) + "],\n"));
@ -485,14 +484,18 @@ class RolesGrantsAndPermissionsGenerator {
}; };
} }
private String toPlPgSqlReference(final PostgresTriggerReference triggerRef, final RbacView.RbacRoleDefinition roleDef) { private String toPlPgSqlReference(
return toVar(roleDef) + final PostgresTriggerReference triggerRef,
(roleDef.getEntityAlias().isGlobal() ? "()" final RbacView.RbacRoleDefinition roleDef,
final boolean assumed) {
final var assumedArg = assumed ? "" : ", unassumed()";
return toRoleRef(roleDef) +
(roleDef.getEntityAlias().isGlobal() ? ( assumed ? "()" : "(unassumed())")
: rbacDef.isRootEntityAlias(roleDef.getEntityAlias()) ? ("(" + triggerRef.name() + ")") : rbacDef.isRootEntityAlias(roleDef.getEntityAlias()) ? ("(" + triggerRef.name() + ")")
: "(" + toTriggerReference(triggerRef, roleDef.getEntityAlias()) + ")"); : "(" + toTriggerReference(triggerRef, roleDef.getEntityAlias()) + assumedArg + ")");
} }
private static String toVar(final RbacView.RbacRoleDefinition roleDef) { private static String toRoleRef(final RbacView.RbacRoleDefinition roleDef) {
return uncapitalize(roleDef.getEntityAlias().simpleName()) + capitalize(roleDef.getRole().roleName()); return uncapitalize(roleDef.getEntityAlias().simpleName()) + capitalize(roleDef.getRole().roleName());
} }

View File

@ -43,8 +43,8 @@ public class TestCustomerEntity implements HasUuid {
.withUpdatableColumns("reference", "prefix", "adminUserName") .withUpdatableColumns("reference", "prefix", "adminUserName")
.createRole(OWNER, (with) -> { .createRole(OWNER, (with) -> {
with.owningUser(CREATOR); with.owningUser(CREATOR).unassumed();
with.incomingSuperRole(GLOBAL, ADMIN); with.incomingSuperRole(GLOBAL, ADMIN).unassumed();
with.permission(DELETE); with.permission(DELETE);
}) })
.createSubRole(ADMIN, (with) -> { .createSubRole(ADMIN, (with) -> {

View File

@ -15,7 +15,6 @@ import java.util.UUID;
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.Permission.*; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.*; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
@ -58,7 +57,7 @@ public class TestPackageEntity implements HasUuid {
.toRole("customer", ADMIN).grantPermission("package", INSERT) .toRole("customer", ADMIN).grantPermission("package", INSERT)
.createRole(OWNER, (with) -> { .createRole(OWNER, (with) -> {
with.incomingSuperRole("customer", ADMIN).unassumed(); with.incomingSuperRole("customer", ADMIN);
with.permission(DELETE); with.permission(DELETE);
with.permission(UPDATE); with.permission(UPDATE);
}) })

View File

@ -203,15 +203,33 @@ create type RbacRoleDescriptor as
( (
objectTable varchar(63), -- for human readability and easier debugging objectTable varchar(63), -- for human readability and easier debugging
objectUuid uuid, objectUuid uuid,
roleType RbacRoleType roleType RbacRoleType,
assumed boolean
); );
create or replace function roleDescriptor(objectTable varchar(63), objectUuid uuid, roleType RbacRoleType) create or replace function assumed()
returns boolean
stable -- leakproof
language sql as $$
select true;
$$;
create or replace function unassumed()
returns boolean
stable -- leakproof
language sql as $$
select false;
$$;
create or replace function roleDescriptor(
objectTable varchar(63), objectUuid uuid, roleType RbacRoleType,
assumed boolean = true) -- just for DSL readability, belongs actually to the grant
returns RbacRoleDescriptor returns RbacRoleDescriptor
returns null on null input returns null on null input
stable -- leakproof stable -- leakproof
language sql as $$ language sql as $$
select objectTable, objectUuid, roleType::RbacRoleType; select objectTable, objectUuid, roleType::RbacRoleType, assumed;
$$; $$;
create or replace function createRole(roleDescriptor RbacRoleDescriptor) create or replace function createRole(roleDescriptor RbacRoleDescriptor)

View File

@ -13,24 +13,6 @@ begin
return createPermissions(forObjectUuid, permitOps); return createPermissions(forObjectUuid, permitOps);
end; $$; end; $$;
create or replace function toRoleUuids(roleDescriptors RbacRoleDescriptor[])
returns uuid[]
language plpgsql
strict as $$
declare
superRoleDescriptor RbacRoleDescriptor;
superRoleUuids uuid[] := array []::uuid[];
begin
foreach superRoleDescriptor in array roleDescriptors
loop
if superRoleDescriptor is not null then
superRoleUuids := superRoleUuids || getRoleId(superRoleDescriptor, 'fail');
end if;
end loop;
return superRoleUuids;
end; $$;
-- ================================================================= -- =================================================================
-- CREATE ROLE -- CREATE ROLE
@ -50,8 +32,10 @@ create or replace function createRoleWithGrants(
language plpgsql as $$ language plpgsql as $$
declare declare
roleUuid uuid; roleUuid uuid;
superRoleUuid uuid; subRoleDesc RbacRoleDescriptor;
superRoleDesc RbacRoleDescriptor;
subRoleUuid uuid; subRoleUuid uuid;
superRoleUuid uuid;
userUuid uuid; userUuid uuid;
grantedByRoleUuid uuid; grantedByRoleUuid uuid;
begin begin
@ -61,14 +45,16 @@ begin
call grantPermissionsToRole(roleUuid, toPermissionUuids(roleDescriptor.objectuuid, permissions)); call grantPermissionsToRole(roleUuid, toPermissionUuids(roleDescriptor.objectuuid, permissions));
end if; end if;
foreach superRoleUuid in array toRoleUuids(incomingSuperRoles) foreach superRoleDesc in array incomingSuperRoles
loop loop
call grantRoleToRole(roleUuid, superRoleUuid); superRoleUuid = getRoleId(superRoleDesc, 'fail');
call grantRoleToRole(roleUuid, superRoleUuid, superRoleDesc.assumed);
end loop; end loop;
foreach subRoleUuid in array toRoleUuids(outgoingSubRoles) foreach subRoleDesc in array outgoingSubRoles
loop loop
call grantRoleToRole(subRoleUuid, roleUuid); subRoleUuid = getRoleId(subRoleDesc, 'fail');
call grantRoleToRole(subRoleUuid, roleUuid, subRoleDesc.assumed);
end loop; end loop;
if cardinality(userUuids) > 0 then if cardinality(userUuids) > 0 then

View File

@ -35,50 +35,50 @@ end; $$;
--changeset rbac-generators-ROLE-DESCRIPTORS:1 endDelimiter:--// --changeset rbac-generators-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
create or replace procedure generateRbacRoleDescriptors(prefix text, targetTable text) create procedure generateRbacRoleDescriptors(prefix text, targetTable text)
language plpgsql as $$ language plpgsql as $$
declare declare
sql text; sql text;
begin begin
sql = format($sql$ sql = format($sql$
create or replace function %1$sOwner(entity %2$s) create or replace function %1$sOwner(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor returns RbacRoleDescriptor
language plpgsql language plpgsql
strict as $f$ strict as $f$
begin begin
return roleDescriptor('%2$s', entity.uuid, 'owner'); return roleDescriptor('%2$s', entity.uuid, 'owner', assumed);
end; $f$; end; $f$;
create or replace function %1$sAdmin(entity %2$s) create or replace function %1$sAdmin(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor returns RbacRoleDescriptor
language plpgsql language plpgsql
strict as $f$ strict as $f$
begin begin
return roleDescriptor('%2$s', entity.uuid, 'admin'); return roleDescriptor('%2$s', entity.uuid, 'admin', assumed);
end; $f$; end; $f$;
create or replace function %1$sAgent(entity %2$s) create or replace function %1$sAgent(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor returns RbacRoleDescriptor
language plpgsql language plpgsql
strict as $f$ strict as $f$
begin begin
return roleDescriptor('%2$s', entity.uuid, 'agent'); return roleDescriptor('%2$s', entity.uuid, 'agent', assumed);
end; $f$; end; $f$;
create or replace function %1$sTenant(entity %2$s) create or replace function %1$sTenant(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor returns RbacRoleDescriptor
language plpgsql language plpgsql
strict as $f$ strict as $f$
begin begin
return roleDescriptor('%2$s', entity.uuid, 'tenant'); return roleDescriptor('%2$s', entity.uuid, 'tenant', assumed);
end; $f$; end; $f$;
create or replace function %1$sGuest(entity %2$s) create or replace function %1$sGuest(entity %2$s, assumed boolean = true)
returns RbacRoleDescriptor returns RbacRoleDescriptor
language plpgsql language plpgsql
strict as $f$ strict as $f$
begin begin
return roleDescriptor('%2$s', entity.uuid, 'guest'); return roleDescriptor('%2$s', entity.uuid, 'guest', assumed);
end; $f$; end; $f$;
$sql$, prefix, targetTable); $sql$, prefix, targetTable);

View File

@ -109,12 +109,12 @@ commit;
/* /*
A global administrator role. A global administrator role.
*/ */
create or replace function globalAdmin() create or replace function globalAdmin(assumed boolean = true)
returns RbacRoleDescriptor returns RbacRoleDescriptor
returns null on null input returns null on null input
stable -- leakproof stable -- leakproof
language sql as $$ language sql as $$
select 'global', (select uuid from RbacObject where objectTable = 'global'), 'admin'::RbacRoleType; select 'global', (select uuid from RbacObject where objectTable = 'global'), 'admin'::RbacRoleType, assumed;
$$; $$;
begin transaction; begin transaction;

View File

@ -0,0 +1,41 @@
### rbac customer 2024-03-08T13:03:39.397294085
```mermaid
%%{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

@ -1,5 +1,5 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-08T08:48:56.112505380. -- This code generated was by RbacViewPostgresGenerator at 2024-03-08T13:03:39.428165899.
-- ============================================================================ -- ============================================================================
--changeset test-customer-rbac-OBJECT:1 endDelimiter:--// --changeset test-customer-rbac-OBJECT:1 endDelimiter:--//
@ -37,7 +37,7 @@ begin
testCustomerOwner(NEW), testCustomerOwner(NEW),
permissions => array['DELETE'], permissions => array['DELETE'],
userUuids => array[currentUserUuid()], userUuids => array[currentUserUuid()],
incomingSuperRoles => array[globalAdmin()] incomingSuperRoles => array[globalAdmin(unassumed())]
); );
perform createRoleWithGrants( perform createRoleWithGrants(

View File

@ -0,0 +1,57 @@
### rbac package 2024-03-08T13:03:39.472333368
```mermaid
%%{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,5 +1,5 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-08T08:48:56.148164198. -- This code generated was by RbacViewPostgresGenerator at 2024-03-08T13:03:39.473061981.
-- ============================================================================ -- ============================================================================
--changeset test-package-rbac-OBJECT:1 endDelimiter:--// --changeset test-package-rbac-OBJECT:1 endDelimiter:--//

View File

@ -6,14 +6,31 @@ import org.junit.jupiter.api.TestInfo;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
@Import(RbacGrantsDiagramService.class) @Import(RbacGrantsDiagramService.class)
public abstract class ContextBasedTest { public abstract class ContextBasedTest {
@Autowired @Autowired
protected Context context; 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 @Autowired
protected RbacGrantsDiagramService diagramService; protected RbacGrantsDiagramService diagramService; // just to be used in subclasses
TestInfo test; TestInfo test;

View File

@ -36,10 +36,10 @@ class TestCustomerEntityTest {
end end
%% granting roles to users %% granting roles to users
user:creator ==> role:customer:owner user:creator ==>|XX| role:customer:owner
%% granting roles to roles %% granting roles to roles
role:global:admin ==> role:customer:owner role:global:admin ==>|XX| role:customer:owner
role:customer:owner ==> role:customer:admin role:customer:owner ==> role:customer:admin
role:customer:admin ==> role:customer:tenant role:customer:admin ==> role:customer:tenant

View File

@ -2,8 +2,6 @@ package net.hostsharing.hsadminng.test.cust;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.context.ContextBasedTest; import net.hostsharing.hsadminng.context.ContextBasedTest;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService;
import net.hostsharing.hsadminng.rbac.rbacgrant.RbacGrantsDiagramService.Include;
import net.hostsharing.test.JpaAttempt; import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -12,14 +10,11 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.PersistenceException; import jakarta.persistence.PersistenceException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static java.util.EnumSet.of;
import static net.hostsharing.test.JpaAttempt.attempt; import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -30,9 +25,6 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
@Autowired @Autowired
TestCustomerRepository testCustomerRepository; TestCustomerRepository testCustomerRepository;
@PersistenceContext
EntityManager em;
@MockBean @MockBean
HttpServletRequest request; HttpServletRequest request;
@ -118,15 +110,15 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
} }
@Test @Test
public void globalAdmin_withAssumedglobalAdminRole_canViewAllCustomers() { public void globalAdmin_withAssumedCustomerOwnerRole_canViewExactlyThatCustomer() {
given: given:
context("superuser-alex@hostsharing.net", "global#global.admin"); context("superuser-alex@hostsharing.net", "test_customer#yyy.owner");
// when // when
final var result = testCustomerRepository.findCustomerByOptionalPrefixLike(null); final var result = testCustomerRepository.findCustomerByOptionalPrefixLike(null);
then: then:
allTheseCustomersAreReturned(result, "xxx", "yyy", "zzz"); allTheseCustomersAreReturned(result, "yyy");
} }
@Test @Test
@ -144,11 +136,6 @@ class TestCustomerRepositoryIntegrationTest extends ContextBasedTest {
@Test @Test
public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnCustomer() { public void customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnCustomer() {
context("customer-admin@xxx.example.com"); context("customer-admin@xxx.example.com");
RbacGrantsDiagramService.writeToFile(
"customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnCustomer",
diagramService.allGrantsToCurrentUser(of(Include.USERS, Include.TEST_ENTITIES, Include.NOT_ASSUMED, Include.DETAILS, Include.PERMISSIONS)),
"doc/customerAdmin_withAssumedOwnedPackageAdminRole_canViewOnlyItsOwnCustomer.md"
);
context("customer-admin@xxx.example.com", "test_package#xxx00.admin"); context("customer-admin@xxx.example.com", "test_package#xxx00.admin");

View File

@ -49,14 +49,11 @@ class TestPackageEntityTest {
end end
end end
%% granting roles to users
user:creator ==> role:package:owner
%% granting roles to roles %% granting roles to roles
role:global:admin -.-> role:customer:owner role:global:admin -.->|XX| role:customer:owner
role:customer:owner -.-> role:customer:admin role:customer:owner -.-> role:customer:admin
role:customer:admin -.-> role:customer:tenant role:customer:admin -.-> role:customer:tenant
role:customer:admin == /// ==> role:package:owner role:customer:admin ==> role:package:owner
role:package:owner ==> role:package:admin role:package:owner ==> role:package:admin
role:package:admin ==> role:package:tenant role:package:admin ==> role:package:tenant
role:package:tenant ==> role:customer:tenant role:package:tenant ==> role:customer:tenant

View File

@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.test.pac; package net.hostsharing.hsadminng.test.pac;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.context.ContextBasedTest;
import net.hostsharing.test.JpaAttempt; import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -19,10 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest @DataJpaTest
@Import( { Context.class, JpaAttempt.class }) @Import( { Context.class, JpaAttempt.class })
class TestPackageRepositoryIntegrationTest { class TestPackageRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
Context context;
@Autowired @Autowired
TestPackageRepository testPackageRepository; TestPackageRepository testPackageRepository;
@ -40,9 +38,10 @@ class TestPackageRepositoryIntegrationTest {
class FindAllByOptionalNameLike { class FindAllByOptionalNameLike {
@Test @Test
public void globalAdmin_withoutAssumedRole_canNotViewAnyPackages_becauseThoseGrantsAreNotassumedd() { public void globalAdmin_withoutAssumedRole_canNotViewAnyPackages_becauseThoseGrantsAreNotAssumed() {
// given // 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 // when
final var result = testPackageRepository.findAllByOptionalNameLike(null); final var result = testPackageRepository.findAllByOptionalNameLike(null);
@ -52,7 +51,7 @@ class TestPackageRepositoryIntegrationTest {
} }
@Test @Test
public void globalAdmin_withAssumedglobalAdminRole__canNotViewAnyPackages_becauseThoseGrantsAreNotassumedd() { public void globalAdmin_withAssumedglobalAdminRole__canNotViewAnyPackages_becauseThoseGrantsAreNotAssumed() {
given: given:
context.define("superuser-alex@hostsharing.net", "global#global.admin"); context.define("superuser-alex@hostsharing.net", "global#global.admin");