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
14 changed files with 333 additions and 276 deletions
Showing only changes of commit e81da57ffd - Show all commits

View File

@ -16,6 +16,7 @@ import net.hostsharing.hsadminng.hs.office.sepamandate.HsOfficeSepaMandateEntity
import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject; import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.hsadminng.test.cust.TestCustomerEntity; import net.hostsharing.hsadminng.test.cust.TestCustomerEntity;
import net.hostsharing.hsadminng.test.dom.TestDomainEntity;
import net.hostsharing.hsadminng.test.pac.TestPackageEntity; import net.hostsharing.hsadminng.test.pac.TestPackageEntity;
import jakarta.persistence.Table; import jakarta.persistence.Table;
@ -596,6 +597,9 @@ public class RbacView {
} }
String getRawTableName() { String getRawTableName() {
if ( aliasName.equals("global")) {
return "global"; // TODO: maybe we should introduce a GlobalEntity class?
}
return withoutRvSuffix(entityClass.getAnnotation(Table.class).name()); return withoutRvSuffix(entityClass.getAnnotation(Table.class).name());
} }
@ -784,6 +788,7 @@ public class RbacView {
Stream.of( Stream.of(
TestCustomerEntity.class, TestCustomerEntity.class,
TestPackageEntity.class, TestPackageEntity.class,
TestDomainEntity.class,
HsOfficePersonEntity.class, HsOfficePersonEntity.class,
HsOfficePartnerEntity.class, HsOfficePartnerEntity.class,
HsOfficePartnerDetailsEntity.class, HsOfficePartnerDetailsEntity.class,

View File

@ -41,6 +41,8 @@ public class TestCustomerEntity implements HasUuid {
.withIdentityView(SQL.projection("prefix")) .withIdentityView(SQL.projection("prefix"))
.withRestrictedViewOrderBy(SQL.expression("reference")) .withRestrictedViewOrderBy(SQL.expression("reference"))
.withUpdatableColumns("reference", "prefix", "adminUserName") .withUpdatableColumns("reference", "prefix", "adminUserName")
// TODO: do we want explicit specification of parent-indenpendent insert permissions?
// .toRole("global", ADMIN).grantPermission("customer", INSERT)
.createRole(OWNER, (with) -> { .createRole(OWNER, (with) -> {
with.owningUser(CREATOR).unassumed(); with.owningUser(CREATOR).unassumed();

View File

@ -0,0 +1,73 @@
package net.hostsharing.hsadminng.test.dom;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
import net.hostsharing.hsadminng.test.pac.TestPackageEntity;
import jakarta.persistence.*;
import java.io.IOException;
import java.util.UUID;
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.Role.*;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
@Entity
@Table(name = "test_domain_rv")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class TestDomainEntity implements HasUuid {
@Id
@GeneratedValue
private UUID uuid;
@Version
private int version;
@ManyToOne(optional = false)
@JoinColumn(name = "packageuuid")
private TestPackageEntity pac;
private String name;
private String description;
public static RbacView rbac() {
return rbacViewFor("domain", TestDomainEntity.class)
.withIdentityView(SQL.projection("name"))
.withUpdatableColumns("version", "packageUuid", "description")
.importEntityAlias("package", TestPackageEntity.class,
dependsOnColumn("packageUuid"),
fetchedBySql("""
SELECT * FROM test_package p
WHERE p.uuid= ${ref}.packageUuid
"""))
.toRole("package", ADMIN).grantPermission("domain", INSERT)
.createRole(OWNER, (with) -> {
with.incomingSuperRole("package", ADMIN);
with.outgoingSubRole("package", TENANT);
with.permission(DELETE);
with.permission(UPDATE);
})
.createSubRole(ADMIN, (with) -> {
with.outgoingSubRole("package", TENANT);
with.permission(SELECT);
});
}
public static void main(String[] args) throws IOException {
rbac().generateWithBaseFileName("133-test-domain-rbac");
}
}

View File

@ -337,10 +337,8 @@ grant all privileges on RbacOwnGrantedPermissions_rv to ${HSADMINNG_POSTGRES_RES
/* /*
Returns all permissions granted to the given user, Returns all permissions granted to the given user,
which are also visible to the current user or assumed roles. which are also visible to the current user or assumed roles.
*/ */
create or replace function grantedPermissions(targetUserUuid uuid) create or replace function grantedPermissionsRaw(targetUserUuid uuid)
returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, opTableName varchar(60), objectTable varchar(60), objectIdName varchar, objectUuid uuid) returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, opTableName varchar(60), objectTable varchar(60), objectIdName varchar, objectUuid uuid)
returns null on null input returns null on null input
language plpgsql as $$ language plpgsql as $$
@ -375,4 +373,15 @@ begin
) xp; ) xp;
-- @formatter:on -- @formatter:on
end; $$; end; $$;
create or replace function grantedPermissions(targetUserUuid uuid)
returns table(roleUuid uuid, roleName text, permissionUuid uuid, op RbacOp, opTableName varchar(60), objectTable varchar(60), objectIdName varchar, objectUuid uuid)
returns null on null input
language sql as $$
select * from grantedPermissionsRaw(targetUserUuid)
union all
select roleUuid, roleName, permissionUuid, 'SELECT'::RbacOp, opTableName, objectTable, objectIdName, objectUuid
from grantedPermissionsRaw(targetUserUuid)
where op <> 'SELECT'::RbacOp;
$$;
--// --//

View File

@ -1,4 +1,4 @@
### rbac customer 2024-03-08T13:03:39.397294085 ### rbac customer 2024-03-09T08:56:16.396142507
```mermaid ```mermaid
%%{init:{'flowchart':{'htmlLabels':false}}}%% %%{init:{'flowchart':{'htmlLabels':false}}}%%

View File

@ -1,5 +1,5 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-08T13:03:39.428165899. -- This code generated was by RbacViewPostgresGenerator at 2024-03-09T08:56:16.421821997.
-- ============================================================================ -- ============================================================================
--changeset test-customer-rbac-OBJECT:1 endDelimiter:--// --changeset test-customer-rbac-OBJECT:1 endDelimiter:--//

View File

@ -1,4 +1,4 @@
### rbac package 2024-03-08T13:03:39.472333368 ### rbac package 2024-03-09T08:56:16.449886471
```mermaid ```mermaid
%%{init:{'flowchart':{'htmlLabels':false}}}%% %%{init:{'flowchart':{'htmlLabels':false}}}%%

View File

@ -1,5 +1,5 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-08T13:03:39.473061981. -- This code generated was by RbacViewPostgresGenerator at 2024-03-09T08:56:16.450322125.
-- ============================================================================ -- ============================================================================
--changeset test-package-rbac-OBJECT:1 endDelimiter:--// --changeset test-package-rbac-OBJECT:1 endDelimiter:--//

View File

@ -1,4 +1,5 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-09T08:56:16.469632602.
-- ============================================================================ -- ============================================================================
--changeset test-domain-rbac-OBJECT:1 endDelimiter:--// --changeset test-domain-rbac-OBJECT:1 endDelimiter:--//
@ -11,91 +12,200 @@ call generateRelatedRbacObject('test_domain');
--changeset test-domain-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// --changeset test-domain-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacRoleDescriptors('testDomain', 'test_domain'); call generateRbacRoleDescriptors('testDomain', 'test_domain');
create or replace function createTestDomainTenantRoleIfNotExists(domain test_domain)
returns uuid
returns null on null input
language plpgsql as $$
declare
domainTenantRoleDesc RbacRoleDescriptor;
domainTenantRoleUuid uuid;
begin
domainTenantRoleDesc = testdomainTenant(domain);
domainTenantRoleUuid = findRoleId(domainTenantRoleDesc);
if domainTenantRoleUuid is not null then
return domainTenantRoleUuid;
end if;
return createRoleWithGrants(
domainTenantRoleDesc,
permissions => array['SELECT'],
incomingSuperRoles => array[testdomainAdmin(domain)]
);
end; $$;
--// --//
-- ============================================================================ -- ============================================================================
--changeset test-domain-rbac-ROLES-CREATION:1 endDelimiter:--// --changeset test-domain-rbac-insert-trigger:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
/* /*
Creates the roles and their assignments for a new domain for the AFTER INSERT TRIGGER. Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
*/ */
create or replace function createRbacRulesForTestDomain() create or replace procedure buildRbacSystemForTestDomain(
NEW test_domain
)
language plpgsql as $$
declare
newPackage test_package;
begin
call enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM test_package p
WHERE p.uuid= NEW.packageUuid
into newPackage;
perform createRoleWithGrants(
testDomainOwner(NEW),
permissions => array['DELETE', 'UPDATE'],
incomingSuperRoles => array[testPackageAdmin(newPackage)],
outgoingSubRoles => array[testPackageTenant(newPackage)]
);
perform createRoleWithGrants(
testDomainAdmin(NEW),
permissions => array['SELECT'],
incomingSuperRoles => array[testDomainOwner(NEW)],
outgoingSubRoles => array[testPackageTenant(newPackage)]
);
call leaveTriggerForObjectUuid(NEW.uuid);
end; $$;
/*
AFTER INSERT TRIGGER to create the role+grant structure for a new test_domain row.
*/
create or replace function insertTriggerForTestDomain_tf()
returns trigger returns trigger
language plpgsql language plpgsql
strict as $$ strict as $$
declare
parentPackage test_package;
begin begin
if TG_OP <> 'INSERT' then call buildRbacSystemForTestDomain(NEW);
raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if;
call enterTriggerForObjectUuid(NEW.uuid);
select * from test_package where uuid = NEW.packageUuid into parentPackage;
-- an owner role is created and assigned to the package's admin group
perform createRoleWithGrants(
testDomainOwner(NEW),
permissions => array['DELETE'],
incomingSuperRoles => array[testPackageAdmin(parentPackage)]
);
-- and a domain admin role is created and assigned to the domain owner as well
perform createRoleWithGrants(
testDomainAdmin(NEW),
permissions => array['UPDATE'],
incomingSuperRoles => array[testDomainOwner(NEW)],
outgoingSubRoles => array[testPackageTenant(parentPackage)]
);
-- a tenent role is only created on demand
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;
create trigger insertTriggerForTestDomain_tg
/* after insert on test_domain
An AFTER INSERT TRIGGER which creates the role structure for a new domain.
*/
drop trigger if exists createRbacRulesForTestDomain_Trigger on test_domain;
create trigger createRbacRulesForTestDomain_Trigger
after insert
on test_domain
for each row for each row
execute procedure createRbacRulesForTestDomain(); execute procedure insertTriggerForTestDomain_tf();
--// --//
-- ============================================================================
--changeset test-domain-rbac-update-trigger:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Called from the AFTER UPDATE TRIGGER to re-wire the grants.
*/
create or replace procedure updateRbacRulesForTestDomain(
OLD test_domain,
NEW test_domain
)
language plpgsql as $$
declare
oldPackage test_package;
newPackage test_package;
begin
call enterTriggerForObjectUuid(NEW.uuid);
SELECT * FROM test_package p
WHERE p.uuid= OLD.packageUuid
into oldPackage;
SELECT * FROM test_package p
WHERE p.uuid= NEW.packageUuid
into newPackage;
if NEW.packageUuid <> OLD.packageUuid then
call revokePermissionFromRole(findPermissionId(OLD.uuid, 'INSERT'), testPackageAdmin(oldPackage));
call revokeRoleFromRole(testDomainOwner(OLD), testPackageAdmin(oldPackage));
call grantRoleToRole(testDomainOwner(NEW), testPackageAdmin(newPackage));
call revokeRoleFromRole(testPackageTenant(oldPackage), testDomainOwner(OLD));
call grantRoleToRole(testPackageTenant(newPackage), testDomainOwner(NEW));
call revokeRoleFromRole(testPackageTenant(oldPackage), testDomainAdmin(OLD));
call grantRoleToRole(testPackageTenant(newPackage), testDomainAdmin(NEW));
end if;
call leaveTriggerForObjectUuid(NEW.uuid);
end; $$;
/*
AFTER INSERT TRIGGER to re-wire the grant structure for a new test_domain row.
*/
create or replace function updateTriggerForTestDomain_tf()
returns trigger
language plpgsql
strict as $$
begin
call updateRbacRulesForTestDomain(OLD, NEW);
return NEW;
end; $$;
create trigger updateTriggerForTestDomain_tg
after update on test_domain
for each row
execute procedure updateTriggerForTestDomain_tf();
--//
-- ============================================================================
--changeset test-domain-rbac-INSERT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates INSERT INTO test_domain permissions for the related test_package rows.
*/
do language plpgsql $$
declare
row test_package;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO test_domain permissions for the related test_package rows');
FOR row IN SELECT * FROM test_package
LOOP
roleUuid := findRoleId(testPackageAdmin(row));
permissionUuid := createPermission(row.uuid, 'INSERT', 'test_domain');
call grantPermissionToRole(roleUuid, permissionUuid);
END LOOP;
END;
$$;
/**
Adds test_domain INSERT permission to specified role of new test_package rows.
*/
create or replace function test_domain_test_package_insert_tf()
returns trigger
language plpgsql
strict as $$
begin
call grantPermissionToRole(
testPackageAdmin(NEW),
createPermission(NEW.uuid, 'INSERT', 'test_domain'));
return NEW;
end; $$;
create trigger test_domain_test_package_insert_tg
after insert on test_package
for each row
execute procedure test_domain_test_package_insert_tf();
/**
Checks if the user or assumed roles are allowed to insert a row to test_domain.
*/
create or replace function test_domain_insert_permission_missing_tf()
returns trigger
language plpgsql as $$
begin
raise exception '[403] insert into test_domain not allowed for current subjects % (%)',
currentSubjects(), currentSubjectsUuids();
end; $$;
create trigger test_domain_insert_permission_check_tg
before insert on test_domain
for each row
when ( not hasInsertPermission(NEW.packageUuid, 'INSERT', 'test_domain') )
execute procedure test_domain_insert_permission_missing_tf();
--//
-- ============================================================================ -- ============================================================================
--changeset test-domain-rbac-IDENTITY-VIEW:1 endDelimiter:--// --changeset test-domain-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacIdentityView('test_domain', $idName$ call generateRbacIdentityView('test_domain', $idName$
target.name name
$idName$); $idName$);
--// --//
@ -103,15 +213,13 @@ call generateRbacIdentityView('test_domain', $idName$
-- ============================================================================ -- ============================================================================
--changeset test-domain-rbac-RESTRICTED-VIEW:1 endDelimiter:--// --changeset test-domain-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacRestrictedView('test_domain',
/* 'name',
Creates a view to the customer main table which maps the identifying name $updates$
(in this case, the prefix) to the objectUuid. version = new.version,
*/ packageUuid = new.packageUuid,
drop view if exists test_domain_rv; description = new.description
create or replace view test_domain_rv as $updates$);
select target.*
from test_domain as target
where target.uuid in (select queryAccessibleObjectUuidsOfSubjectIds('SELECT', 'domain', currentSubjectsUuids()));
grant all privileges on test_domain_rv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
--// --//

View File

@ -42,151 +42,3 @@ subgraph hsOfficeRelationship
end end
``` ```
if TG_OP = 'INSERT' then
-- the owner role with full access for admins of the relAnchor global admins
ownerRole = createRole(
hsOfficeRelationshipOwner(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['*']),
beneathRoles(array[
globalAdmin(),
hsOfficePersonAdmin(newRelAnchor)])
);
-- the admin role with full access for the owner
adminRole = createRole(
hsOfficeRelationshipAdmin(NEW),
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['edit']),
beneathRole(ownerRole)
);
-- the tenant role for those related users who can view the data
perform createRole(
hsOfficeRelationshipTenant,
grantingPermissions(forObjectUuid => NEW.uuid, permitOps => array ['view']),
beneathRoles(array[
hsOfficePersonAdmin(newRelAnchor),
hsOfficePersonAdmin(newRelHolder),
hsOfficeContactAdmin(newContact)]),
withSubRoles(array[
hsOfficePersonTenant(newRelAnchor),
hsOfficePersonTenant(newRelHolder),
hsOfficeContactTenant(newContact)])
);
-- anchor and holder admin roles need each others tenant role
-- to be able to see the joined relationship
call grantRoleToRole(hsOfficePersonTenant(newRelAnchor), hsOfficePersonAdmin(newRelHolder));
call grantRoleToRole(hsOfficePersonTenant(newRelHolder), hsOfficePersonAdmin(newRelAnchor));
call grantRoleToRoleIfNotNull(hsOfficePersonTenant(newRelHolder), hsOfficeContactAdmin(newContact));
elsif TG_OP = 'UPDATE' then
if OLD.contactUuid <> NEW.contactUuid then
-- nothing but the contact can be updated,
-- in other cases, a new relationship needs to be created and the old updated
select * from hs_office_contact as c where c.uuid = OLD.contactUuid into oldContact;
call revokeRoleFromRole( hsOfficeRelationshipTenant, hsOfficeContactAdmin(oldContact) );
call grantRoleToRole( hsOfficeRelationshipTenant, hsOfficeContactAdmin(newContact) );
call revokeRoleFromRole( hsOfficeContactTenant(oldContact), hsOfficeRelationshipTenant );
call grantRoleToRole( hsOfficeContactTenant(newContact), hsOfficeRelationshipTenant );
end if;
else
raise exception 'invalid usage of TRIGGER';
end if;
return NEW;
end; $$;
/*
An AFTER INSERT TRIGGER which creates the role structure for a new customer.
*/
create trigger createRbacRolesForHsOfficeRelationship_Trigger
after insert
on hs_office_relationship
for each row
execute procedure hsOfficeRelationshipRbacRolesTrigger();
/*
An AFTER UPDATE TRIGGER which updates the role structure of a customer.
*/
create trigger updateRbacRolesForHsOfficeRelationship_Trigger
after update
on hs_office_relationship
for each row
execute procedure hsOfficeRelationshipRbacRolesTrigger();
--//
-- ============================================================================
--changeset hs-office-relationship-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacIdentityView('hs_office_relationship', $idName$
(select idName from hs_office_person_iv p where p.uuid = target.relAnchorUuid)
|| '-with-' || target.relType || '-' ||
(select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)
$idName$);
--//
-- ============================================================================
--changeset hs-office-relationship-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRbacRestrictedView('hs_office_relationship',
'(select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)',
$updates$
contactUuid = new.contactUuid
$updates$);
--//
-- TODO: exception if one tries to amend any other column
-- ============================================================================
--changeset hs-office-relationship-rbac-NEW-RELATHIONSHIP:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates a global permission for new-relationship and assigns it to the hostsharing admins role.
*/
do language plpgsql $$
declare
addCustomerPermissions uuid[];
globalObjectUuid uuid;
globalAdminRoleUuid uuid ;
begin
call defineContext('granting global new-relationship permission to global admin role', null, null, null);
globalAdminRoleUuid := findRoleId(globalAdmin());
globalObjectUuid := (select uuid from global);
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-relationship']);
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
end;
$$;
/**
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
*/
create or replace function addHsOfficeRelationshipNotAllowedForCurrentSubjects()
returns trigger
language PLPGSQL
as $$
begin
raise exception '[403] new-relationship not permitted for %',
array_to_string(currentSubjects(), ';', 'null');
end; $$;
/**
Checks if the user or assumed roles are allowed to create a new customer.
*/
create trigger hs_office_relationship_insert_trigger
before insert
on hs_office_relationship
for each row
-- TODO.spec: who is allowed to create new relationships
when ( not hasAssumedRole() )
execute procedure addHsOfficeRelationshipNotAllowedForCurrentSubjects();
--//

View File

@ -28,6 +28,7 @@ public class ArchitectureTest {
"..test", "..test",
"..test.cust", "..test.cust",
"..test.pac", "..test.pac",
"..test.dom",
"..context", "..context",
"..generated..", "..generated..",
"..persistence..", "..persistence..",

View File

@ -62,6 +62,7 @@ class RbacGrantsDiagramServiceIntegrationTest extends ContextBasedTestWithCleanu
role:test_domain#xxx00-aaaa.admin --> role:test_package#xxx00.tenant 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_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 role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant
""".trim()); """.trim());
} }
@ -75,10 +76,12 @@ class RbacGrantsDiagramServiceIntegrationTest extends ContextBasedTestWithCleanu
flowchart TB flowchart TB
role:test_customer#xxx.tenant --> perm:SELECT:on:test_customer#xxx role:test_customer#xxx.tenant --> perm:SELECT:on:test_customer#xxx
role:test_domain#xxx00-aaaa.admin --> perm:UPDATE:on:test_domain#xxx00-aaaa 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.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: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_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 --> perm:SELECT:on:test_package#xxx00
role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant role:test_package#xxx00.tenant --> role:test_customer#xxx.tenant
""".trim()); """.trim());

View File

@ -295,7 +295,8 @@ class RbacUserControllerAcceptanceTest {
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"), hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
hasEntry("op", "DELETE")) hasEntry("op", "DELETE"))
)) ))
.body("size()", is(6)); // actual content tested in integration test, so this is enough for here:
.body("size()", greaterThanOrEqualTo(6));
// @formatter:on // @formatter:on
} }
@ -325,7 +326,8 @@ class RbacUserControllerAcceptanceTest {
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"), hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
hasEntry("op", "DELETE")) hasEntry("op", "DELETE"))
)) ))
.body("size()", is(6)); // actual content tested in integration test, so this is enough for here:
.body("size()", greaterThanOrEqualTo(6));
// @formatter:on // @formatter:on
} }
@ -354,7 +356,8 @@ class RbacUserControllerAcceptanceTest {
hasEntry("roleName", "test_domain#yyy00-aaaa.owner"), hasEntry("roleName", "test_domain#yyy00-aaaa.owner"),
hasEntry("op", "DELETE")) hasEntry("op", "DELETE"))
)) ))
.body("size()", is(6)); // actual content tested in integration test, so this is enough for here:
.body("size()", greaterThanOrEqualTo(6));
// @formatter:on // @formatter:on
} }

View File

@ -20,6 +20,7 @@ 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.Comparator.comparing;
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;
@ -181,8 +182,6 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
private static final String[] ALL_USER_PERMISSIONS = Array.of( private static final String[] ALL_USER_PERMISSIONS = Array.of(
// @formatter:off // @formatter:off
"global#global.admin -> global#global: add-customer",
"test_customer#xxx.admin -> test_customer#xxx: SELECT", "test_customer#xxx.admin -> test_customer#xxx: SELECT",
"test_customer#xxx.owner -> test_customer#xxx: DELETE", "test_customer#xxx.owner -> test_customer#xxx: DELETE",
"test_customer#xxx.tenant -> test_customer#xxx: SELECT", "test_customer#xxx.tenant -> test_customer#xxx: SELECT",
@ -233,7 +232,9 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
// when // 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 // then
allTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS); allTheseRbacPermissionsAreReturned(result, ALL_USER_PERMISSIONS);