Compare commits

...

8 Commits

Author SHA1 Message Date
Michael Hoennig
e272b5b2ae amend test data to new grant structure (e.g. person with referrer but no guest+tenant roles) 2024-02-12 20:01:19 +01:00
Michael Hoennig
2df5ddd87e Merge branch 'add-trigger-object-to-rbacgrant' into remove-direct-partner-person-and-contact
# Conflicts:
#	src/main/resources/db/changelog/233-hs-office-partner-rbac.sql
#	src/test/java/net/hostsharing/hsadminng/hs/office/migration/ImportOfficeData.java
2024-02-12 18:22:10 +01:00
Michael Hoennig
fd1466c667 cleanup 2024-02-12 16:50:57 +01:00
Michael Hoennig
607a6c9424 references and on delete cascade 2024-02-12 16:21:01 +01:00
Michael Hoennig
db76a57807 add rbacgrants.grantedByTriggerOf (WIP: references and delete trigger/cascade still missing) 2024-02-12 15:38:31 +01:00
Michael Hoennig
201a8d34af remove precondition checks, now covered by checks in @BeforeEach and @AfterEach 2024-02-12 13:06:54 +01:00
Michael Hoennig
f71b769cb9 WIP: implement an endpoint to create a Mermaid flowchart with all grants of a given user 2024-02-12 12:27:02 +01:00
496cdf295b fix import error for missing contractual contact and legacy-ids (#17)
Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: #17
Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
2024-02-05 14:37:50 +01:00
23 changed files with 163 additions and 65 deletions

View File

@ -95,7 +95,7 @@ public class RbacGrantController implements RbacGrantsApi {
return ResponseEntity.noContent().build(); return ResponseEntity.noContent().build();
} }
// TODO: implement an endpoint to create a Mermaid flowchart with all grants of a given user
// @GetMapping( // @GetMapping(
// path = "/api/rbac/users/{userUuid}/grants", // path = "/api/rbac/users/{userUuid}/grants",
// produces = {"text/vnd.mermaid"}) // produces = {"text/vnd.mermaid"})

View File

@ -5,7 +5,6 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import java.util.List; import java.util.List;
import java.util.UUID;
public interface RbacGrantRepository extends Repository<RbacGrantEntity, RbacGrantId> { public interface RbacGrantRepository extends Repository<RbacGrantEntity, RbacGrantId> {

View File

@ -102,4 +102,3 @@ public class RbacUserController implements RbacUsersApi {
RbacUserPermissionResource.class)); RbacUserPermissionResource.class));
} }
} }

View File

@ -471,12 +471,13 @@ $$;
create table RbacGrants create table RbacGrants
( (
uuid uuid primary key default uuid_generate_v4(), uuid uuid primary key default uuid_generate_v4(),
grantedByTriggerOf uuid references RbacObject (uuid) on delete cascade initially deferred ,
grantedByRoleUuid uuid references RbacRole (uuid), grantedByRoleUuid uuid references RbacRole (uuid),
ascendantUuid uuid references RbacReference (uuid), ascendantUuid uuid references RbacReference (uuid),
descendantUuid uuid references RbacReference (uuid), descendantUuid uuid references RbacReference (uuid),
assumed boolean not null default true, -- auto assumed (true) vs. needs assumeRoles (false) assumed boolean not null default true, -- auto assumed (true) vs. needs assumeRoles (false)
unique (ascendantUuid, descendantUuid) unique (ascendantUuid, descendantUuid),
); constraint rbacGrant_createdBy check ( grantedByRoleUuid is null or grantedByTriggerOf is null) );
create index on RbacGrants (ascendantUuid); create index on RbacGrants (ascendantUuid);
create index on RbacGrants (descendantUuid); create index on RbacGrants (descendantUuid);
@ -580,8 +581,8 @@ begin
perform assertReferenceType('permissionId (descendant)', permissionIds[i], 'RbacPermission'); perform assertReferenceType('permissionId (descendant)', permissionIds[i], 'RbacPermission');
insert insert
into RbacGrants (ascendantUuid, descendantUuid, assumed) into RbacGrants (grantedByTriggerOf, ascendantUuid, descendantUuid, assumed)
values (roleUuid, permissionIds[i], true) values (currentTriggerObjectUuid(), roleUuid, permissionIds[i], true)
on conflict do nothing; -- allow granting multiple times on conflict do nothing; -- allow granting multiple times
end loop; end loop;
end; end;
@ -598,8 +599,8 @@ begin
end if; end if;
insert insert
into RbacGrants (ascendantuuid, descendantUuid, assumed) into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed)
values (superRoleId, subRoleId, doAssume) values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume)
on conflict do nothing; -- allow granting multiple times on conflict do nothing; -- allow granting multiple times
end; $$; end; $$;
@ -621,8 +622,8 @@ begin
end if; end if;
insert insert
into RbacGrants (ascendantuuid, descendantUuid, assumed) into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed)
values (superRoleId, subRoleId, doAssume) values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume)
on conflict do nothing; -- allow granting multiple times on conflict do nothing; -- allow granting multiple times
end; $$; end; $$;
@ -644,8 +645,8 @@ begin
end if; end if;
insert insert
into RbacGrants (ascendantuuid, descendantUuid, assumed) into RbacGrants (grantedByTriggerOf, ascendantuuid, descendantUuid, assumed)
values (superRoleId, subRoleId, doAssume) values (currentTriggerObjectUuid(), superRoleId, subRoleId, doAssume)
on conflict do nothing; -- allow granting multiple times on conflict do nothing; -- allow granting multiple times
end; $$; end; $$;

View File

@ -56,6 +56,7 @@ drop view if exists rbacgrants_ev;
create or replace view rbacgrants_ev as create or replace view rbacgrants_ev as
-- @formatter:off -- @formatter:off
select x.grantUuid as uuid, select x.grantUuid as uuid,
x.grantedByTriggerOf as grantedByTriggerOf,
go.objectTable || '#' || findIdNameByObjectUuid(go.objectTable, go.uuid) || '.' || r.roletype as grantedByRoleIdName, go.objectTable || '#' || findIdNameByObjectUuid(go.objectTable, go.uuid) || '.' || r.roletype as grantedByRoleIdName,
x.ascendingIdName as ascendantIdName, x.ascendingIdName as ascendantIdName,
x.descendingIdName as descendantIdName, x.descendingIdName as descendantIdName,
@ -65,6 +66,7 @@ create or replace view rbacgrants_ev as
x.assumed x.assumed
from ( from (
select g.uuid as grantUuid, select g.uuid as grantUuid,
g.grantedbytriggerof as grantedbytriggerof,
g.grantedbyroleuuid, g.ascendantuuid, g.descendantuuid, g.assumed, g.grantedbyroleuuid, g.ascendantuuid, g.descendantuuid, g.assumed,
coalesce( coalesce(

View File

@ -0,0 +1,61 @@
--liquibase formatted sql
-- ============================================================================
--changeset rbac-trigger-context-ENTER:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
create or replace procedure enterTriggerForObjectUuid(currentObjectUuid uuid)
language plpgsql as $$
declare
existingObjectUuid text;
begin
existingObjectUuid = current_setting('hsadminng.currentObjectUuid', true);
if (existingObjectUuid > '' ) then
raise exception '[500] currentObjectUuid already defined, already in trigger of "%"', existingObjectUuid;
end if;
execute format('set local hsadminng.currentObjectUuid to %L', currentObjectUuid);
end; $$;
-- ============================================================================
--changeset rbac-trigger-context-CURRENT-ID:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Returns the uuid of the object uuid whose trigger is currently executed as set via `enterTriggerForObjectUuid(...)`.
*/
create or replace function currentTriggerObjectUuid()
returns uuid
stable -- leakproof
language plpgsql as $$
declare
currentObjectUuid uuid;
begin
begin
currentObjectUuid = current_setting('hsadminng.currentObjectUuid')::uuid;
return currentObjectUuid;
exception
when others then
return null::uuid;
end;
end; $$;
--//
-- ============================================================================
--changeset rbac-trigger-context-LEAVE:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
create or replace procedure leaveTriggerForObjectUuid(currentObjectUuid uuid)
language plpgsql as $$
declare
existingObjectUuid uuid;
begin
existingObjectUuid = current_setting('hsadminng.currentObjectUuid', true);
if ( existingObjectUuid <> currentObjectUuid ) then
raise exception '[500] currentObjectUuid does not match: "%"', existingObjectUuid;
end if;
execute format('reset hsadminng.currentObjectUuid');
end; $$;

View File

@ -34,6 +34,8 @@ begin
raise exception 'invalid usage of TRIGGER AFTER INSERT'; raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if; end if;
call enterTriggerForObjectUuid(NEW.uuid);
-- the owner role with full access for Hostsharing administrators -- the owner role with full access for Hostsharing administrators
testCustomerOwnerUuid = createRoleWithGrants( testCustomerOwnerUuid = createRoleWithGrants(
testCustomerOwner(NEW), testCustomerOwner(NEW),
@ -59,6 +61,7 @@ begin
permissions => array['view'] permissions => array['view']
); );
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -26,13 +26,13 @@ create or replace function createRbacRolesForTestPackage()
strict as $$ strict as $$
declare declare
parentCustomer test_customer; parentCustomer test_customer;
packageOwnerRoleUuid uuid;
packageAdminRoleUuid uuid;
begin begin
if TG_OP <> 'INSERT' then if TG_OP <> 'INSERT' then
raise exception 'invalid usage of TRIGGER AFTER INSERT'; raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if; end if;
call enterTriggerForObjectUuid(NEW.uuid);
select * from test_customer as c where c.uuid = NEW.customerUuid into parentCustomer; select * from test_customer as c where c.uuid = NEW.customerUuid into parentCustomer;
-- an owner role is created and assigned to the customer's admin role -- an owner role is created and assigned to the customer's admin role
@ -57,6 +57,7 @@ begin
outgoingSubRoles => array[testCustomerTenant(parentCustomer)] outgoingSubRoles => array[testCustomerTenant(parentCustomer)]
); );
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -53,6 +53,8 @@ begin
raise exception 'invalid usage of TRIGGER AFTER INSERT'; raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if; end if;
call enterTriggerForObjectUuid(NEW.uuid);
select * from test_package where uuid = NEW.packageUuid into parentPackage; select * from test_package where uuid = NEW.packageUuid into parentPackage;
-- an owner role is created and assigned to the package's admin group -- an owner role is created and assigned to the package's admin group
@ -72,6 +74,7 @@ begin
-- a tenent role is only created on demand -- a tenent role is only created on demand
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -70,6 +70,7 @@ do language plpgsql $$
call createHsOfficePersonTestData('LP', 'Fourth eG'); call createHsOfficePersonTestData('LP', 'Fourth eG');
call createHsOfficePersonTestData('UF', 'Erben Bessler', 'Mel', 'Bessler'); call createHsOfficePersonTestData('UF', 'Erben Bessler', 'Mel', 'Bessler');
call createHsOfficePersonTestData('NP', null, 'Bessler', 'Anita'); call createHsOfficePersonTestData('NP', null, 'Bessler', 'Anita');
call createHsOfficePersonTestData('NP', null, 'Bessler', 'Bert');
call createHsOfficePersonTestData('NP', null, 'Winkler', 'Paul'); call createHsOfficePersonTestData('NP', null, 'Winkler', 'Paul');
end; end;
$$; $$;

View File

@ -32,6 +32,7 @@ declare
oldContact hs_office_contact; oldContact hs_office_contact;
newContact hs_office_contact; newContact hs_office_contact;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_person as p where p.uuid = NEW.relAnchorUuid into newAnchorPerson; select * from hs_office_person as p where p.uuid = NEW.relAnchorUuid into newAnchorPerson;
select * from hs_office_person as p where p.uuid = NEW.relHolderUuid into newHolderPerson; select * from hs_office_person as p where p.uuid = NEW.relHolderUuid into newHolderPerson;
@ -92,16 +93,17 @@ begin
select * from hs_office_contact as c where c.uuid = OLD.contactUuid into oldContact; select * from hs_office_contact as c where c.uuid = OLD.contactUuid into oldContact;
call revokeRoleFromRole( hsOfficeRelationshipTenant(NEW), hsOfficeContactAdmin(oldContact) ); call revokeRoleFromRole( hsOfficeContactReferrer(oldContact), hsOfficeRelationshipTenant(NEW) );
call grantRoleToRole( hsOfficeRelationshipTenant(NEW), hsOfficeContactAdmin(newContact) ); call grantRoleToRole( hsOfficeContactReferrer(newContact), hsOfficeRelationshipTenant(NEW) );
call revokeRoleFromRole( hsOfficeContactAdmin(oldContact), hsOfficeRelationshipAgent(NEW) ); call revokeRoleFromRole( hsOfficeRelationshipAgent(NEW), hsOfficeContactAdmin(oldContact) );
call grantRoleToRole( hsOfficeContactAdmin(newContact), hsOfficeRelationshipAgent(NEW) ); call grantRoleToRole( hsOfficeRelationshipAgent(NEW), hsOfficeContactAdmin(newContact) );
end if; end if;
else else
raise exception 'invalid usage of TRIGGER'; raise exception 'invalid usage of TRIGGER';
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -24,6 +24,8 @@ declare
newPartnerRole hs_office_relationship; newPartnerRole hs_office_relationship;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_relationship as r where r.uuid = NEW.partnerroleuuid into newPartnerRole; select * from hs_office_relationship as r where r.uuid = NEW.partnerroleuuid into newPartnerRole;
if TG_OP = 'INSERT' then if TG_OP = 'INSERT' then
@ -118,6 +120,7 @@ begin
raise exception 'invalid usage of TRIGGER'; raise exception 'invalid usage of TRIGGER';
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -30,6 +30,7 @@ declare
newHsOfficeDebitor hs_office_debitor; newHsOfficeDebitor hs_office_debitor;
newHsOfficeBankAccount hs_office_bankAccount; newHsOfficeBankAccount hs_office_bankAccount;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_debitor as p where p.uuid = NEW.debitorUuid into newHsOfficeDebitor; select * from hs_office_debitor as p where p.uuid = NEW.debitorUuid into newHsOfficeDebitor;
select * from hs_office_bankAccount as c where c.uuid = NEW.bankAccountUuid into newHsOfficeBankAccount; select * from hs_office_bankAccount as c where c.uuid = NEW.bankAccountUuid into newHsOfficeBankAccount;
@ -75,6 +76,7 @@ begin
raise exception 'invalid usage of TRIGGER'; raise exception 'invalid usage of TRIGGER';
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -37,6 +37,7 @@ declare
newBankAccount hs_office_bankaccount; newBankAccount hs_office_bankaccount;
oldBankAccount hs_office_bankaccount; oldBankAccount hs_office_bankaccount;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
hsOfficeDebitorTenant := hsOfficeDebitorTenant(NEW); hsOfficeDebitorTenant := hsOfficeDebitorTenant(NEW);
@ -147,6 +148,7 @@ begin
raise exception 'invalid usage of TRIGGER'; raise exception 'invalid usage of TRIGGER';
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -31,6 +31,7 @@ declare
newHsOfficePartnerRel hs_office_relationship; newHsOfficePartnerRel hs_office_relationship;
newHsOfficeDebitor hs_office_debitor; newHsOfficeDebitor hs_office_debitor;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_partner as p where p.uuid = NEW.partnerUuid into newHsOfficePartner; select * from hs_office_partner as p where p.uuid = NEW.partnerUuid into newHsOfficePartner;
select * from hs_office_relationship as r where r.relType = 'PARTNER' and r.relHolderUuid = NEW.partnerUuid into newHsOfficePartnerRel; select * from hs_office_relationship as r where r.relType = 'PARTNER' and r.relHolderUuid = NEW.partnerUuid into newHsOfficePartnerRel;
@ -76,6 +77,7 @@ begin
raise exception 'invalid usage of TRIGGER'; raise exception 'invalid usage of TRIGGER';
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -29,6 +29,7 @@ create or replace function hsOfficeCoopSharesTransactionRbacRolesTrigger()
declare declare
newHsOfficeMembership hs_office_membership; newHsOfficeMembership hs_office_membership;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership; select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership;
@ -49,6 +50,7 @@ begin
raise exception 'invalid usage of TRIGGER'; raise exception 'invalid usage of TRIGGER';
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -29,6 +29,7 @@ create or replace function hsOfficeCoopAssetsTransactionRbacRolesTrigger()
declare declare
newHsOfficeMembership hs_office_membership; newHsOfficeMembership hs_office_membership;
begin begin
call enterTriggerForObjectUuid(NEW.uuid);
select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership; select * from hs_office_membership as p where p.uuid = NEW.membershipUuid into newHsOfficeMembership;
@ -49,6 +50,7 @@ begin
raise exception 'invalid usage of TRIGGER'; raise exception 'invalid usage of TRIGGER';
end if; end if;
call leaveTriggerForObjectUuid(NEW.uuid);
return NEW; return NEW;
end; $$; end; $$;

View File

@ -25,6 +25,8 @@ databaseChangeLog:
file: db/changelog/054-rbac-context.sql file: db/changelog/054-rbac-context.sql
- include: - include:
file: db/changelog/055-rbac-views.sql file: db/changelog/055-rbac-views.sql
- include:
file: db/changelog/056-rbac-trigger-context.sql
- include: - include:
file: db/changelog/057-rbac-role-builder.sql file: db/changelog/057-rbac-role-builder.sql
- include: - include:

View File

@ -105,18 +105,15 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTestWithClean
initialRoleNames, initialRoleNames,
"hs_office_contact#anothernewcontact.owner", "hs_office_contact#anothernewcontact.owner",
"hs_office_contact#anothernewcontact.admin", "hs_office_contact#anothernewcontact.admin",
"hs_office_contact#anothernewcontact.tenant", "hs_office_contact#anothernewcontact.referrer"
"hs_office_contact#anothernewcontact.guest"
)); ));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.from( assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.from(
initialGrantNames, initialGrantNames,
"{ grant role hs_office_contact#anothernewcontact.owner to role global#global.admin by system and assume }", "{ 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 edit 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 * 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 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 view on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.referrer 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 }" "{ grant role hs_office_contact#anothernewcontact.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }"
)); ));
} }

View File

@ -600,6 +600,7 @@ public class ImportOfficeData extends ContextBasedTest {
Map<Integer, E> entities, Map<Integer, E> entities,
final String legacyIdTable, final String legacyIdTable,
final String legacyIdColumn) { final String legacyIdColumn) {
em.flush();
entities.forEach((id, entity) -> em.createNativeQuery(""" entities.forEach((id, entity) -> em.createNativeQuery("""
UPDATE ${legacyIdTable} UPDATE ${legacyIdTable}
SET ${legacyIdColumn} = :legacyId SET ${legacyIdColumn} = :legacyId
@ -879,13 +880,13 @@ public class ImportOfficeData extends ContextBasedTest {
partners.forEach( (id, partner) -> { partners.forEach( (id, partner) -> {
final var partnerPerson = partner.getPartnerRole().getRelHolder(); final var partnerPerson = partner.getPartnerRole().getRelHolder();
if (relationships.values().stream() if (relationships.values().stream()
.filter(rel -> rel.getRelHolder() == partnerPerson && rel.getRelType() == HsOfficeRelationshipType.REPRESENTATIVE) .filter(rel -> rel.getRelAnchor() == partnerPerson && rel.getRelType() == HsOfficeRelationshipType.REPRESENTATIVE)
.findFirst().isEmpty()) { .findFirst().isEmpty()) {
addRelationship(partnerPerson, partnerPerson, partner.getPartnerRole().getContact(), HsOfficeRelationshipType.REPRESENTATIVE); //addRelationship(partnerPerson, partnerPerson, partner.getPartnerRole().getContact(), HsOfficeRelationshipType.REPRESENTATIVE);
contractualMissing.add(partner.getPartnerNumber()); contractualMissing.add(partner.getPartnerNumber());
} }
}); });
// assertThat(contractualMissing).isEmpty(); uncomment if we don't want allow missing contractual contact //assertThat(contractualMissing).isEmpty(); // comment out if we do want to allow missing contractual contact
} }
private static boolean containsRole(final Record rec, final String role) { private static boolean containsRole(final Record rec, final String role) {
final var roles = rec.getString("roles"); final var roles = rec.getString("roles");

View File

@ -14,7 +14,6 @@ import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
import net.hostsharing.test.Array; import net.hostsharing.test.Array;
import net.hostsharing.test.JpaAttempt; import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@ -106,20 +106,20 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTestWithCleanu
initialRoleNames, initialRoleNames,
"hs_office_person#anothernewperson.owner", "hs_office_person#anothernewperson.owner",
"hs_office_person#anothernewperson.admin", "hs_office_person#anothernewperson.admin",
"hs_office_person#anothernewperson.tenant", "hs_office_person#anothernewperson.referrer"
"hs_office_person#anothernewperson.guest"
)); ));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder( assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(
Array.from( Array.from(
initialGrantNames, 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 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 * on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.owner by system and assume }",
"{ grant role hs_office_person#anothernewperson.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }",
"{ 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 role hs_office_person#anothernewperson.admin 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 role hs_office_person#anothernewperson.guest to role hs_office_person#anothernewperson.tenant by system and assume }", "{ grant perm view on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.referrer by system and assume }",
"{ grant role hs_office_person#anothernewperson.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }" "{ grant role hs_office_person#anothernewperson.referrer to role hs_office_person#anothernewperson.admin by system and assume }"
)); ));
} }

View File

@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.office.relationship;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRepository;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType;
import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.hs.office.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository; import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
@ -26,6 +25,8 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.NATURAL_PERSON;
import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.UNINCORPORATED_FIRM;
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf; import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf;
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf; import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.distinctRoleNamesOf;
import static net.hostsharing.test.JpaAttempt.attempt; import static net.hostsharing.test.JpaAttempt.attempt;
@ -67,9 +68,14 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var count = relationshipRepo.count(); final var count = relationshipRepo.count();
final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Bessler").get(0); final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Bessler").stream()
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike("Anita").get(0); .filter(p -> p.getPersonType() == UNINCORPORATED_FIRM)
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth contact").get(0); .findFirst().orElseThrow();
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike("Paul").stream()
.filter(p -> p.getPersonType() == NATURAL_PERSON)
.findFirst().orElseThrow();
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth contact").stream()
.findFirst().orElseThrow();
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
@ -98,9 +104,14 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
// when // when
attempt(em, () -> { attempt(em, () -> {
final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Bessler").get(0); final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Bessler").stream()
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike("Anita").get(0); .filter(p -> p.getPersonType() == UNINCORPORATED_FIRM)
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth contact").get(0); .findFirst().orElseThrow();
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike("Bert").stream()
.filter(p -> p.getPersonType() == NATURAL_PERSON)
.findFirst().orElseThrow();
final var givenContact = contactRepo.findContactByOptionalLabelLike("fourth contact").stream()
.findFirst().orElseThrow();
final var newRelationship = HsOfficeRelationshipEntity.builder() final var newRelationship = HsOfficeRelationshipEntity.builder()
.relAnchor(givenAnchorPerson) .relAnchor(givenAnchorPerson)
.relHolder(givenHolderPerson) .relHolder(givenHolderPerson)
@ -113,26 +124,33 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
// then // then
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(Array.from( assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(Array.from(
initialRoleNames, initialRoleNames,
"hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.admin", "hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.owner",
"hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.owner", "hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.admin",
"hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant")); "hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.agent",
"hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.tenant"));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted( assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, 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 * on hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.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#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.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 edit on hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.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 role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.admin to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.owner by system and assume }",
"{ grant role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.admin to role hs_office_person#ErbenBesslerMelBessler.admin 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 role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.agent to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.admin 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#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.agent 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 }", "{ grant role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.agent to role hs_office_person#BesslerBert.admin by system and assume }",
"{ grant perm view on hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.tenant by system and assume }",
"{ grant role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.tenant to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.agent by system and assume }",
"{ grant role hs_office_person#BesslerBert.referrer to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.tenant by system and assume }",
"{ grant role hs_office_person#ErbenBesslerMelBessler.referrer to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.tenant by system and assume }",
"{ grant role hs_office_contact#fourthcontact.referrer to role hs_office_relationship#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.tenant by system and assume }",
// REPRESENTATIVE holder person -> (represented) anchor person
"{ grant role hs_office_person#BesslerBert.admin to role hs_office_person#ErbenBesslerMelBessler.admin by system and assume }",
"{ grant role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.admin by system and assume }",
"{ grant role hs_office_contact#fourthcontact.tenant to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant by system and assume }",
"{ grant role hs_office_person#BesslerAnita.tenant to role hs_office_relationship#BesslerAnita-with-REPRESENTATIVE-BesslerAnita.tenant by system and assume }",
null) null)
); );
} }
@ -151,7 +169,7 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var person = personRepo.findPersonByOptionalNameLike("Smith").stream() final var person = personRepo.findPersonByOptionalNameLike("Smith").stream()
.filter(p -> p.getPersonType() == HsOfficePersonType.NATURAL_PERSON) .filter(p -> p.getPersonType() == NATURAL_PERSON)
.findFirst().orElseThrow(); .findFirst().orElseThrow();
// when // when
@ -170,7 +188,7 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
// given: // given:
context("person-SmithPeter@example.com"); context("person-SmithPeter@example.com");
final var person = personRepo.findPersonByOptionalNameLike("Smith").stream() final var person = personRepo.findPersonByOptionalNameLike("Smith").stream()
.filter(p -> p.getPersonType() == HsOfficePersonType.NATURAL_PERSON) .filter(p -> p.getPersonType() == NATURAL_PERSON)
.findFirst().orElseThrow(); .findFirst().orElseThrow();
// when: // when:
@ -224,13 +242,13 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenRelationship = givenSomeTemporaryRelationshipBessler( final var givenRelationship = givenSomeTemporaryRelationshipBessler(
"Anita", "fifth contact"); "Bert", "fifth contact");
assertThatRelationshipIsVisibleForUserWithRole( assertThatRelationshipIsVisibleForUserWithRole(
givenRelationship, givenRelationship,
"hs_office_person#ErbenBesslerMelBessler.admin"); "hs_office_person#ErbenBesslerMelBessler.admin");
assertThatRelationshipActuallyInDatabase(givenRelationship); assertThatRelationshipActuallyInDatabase(givenRelationship);
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenContact = contactRepo.findContactByOptionalLabelLike("sixth contact").get(0); final var givenContact = contactRepo.findContactByOptionalLabelLike("sixth contact").stream().findFirst().orElseThrow();
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {
@ -383,10 +401,6 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTestWith
final var initialGrantNames = Array.from(distinctGrantDisplaysOf(rawGrantRepo.findAll())); final var initialGrantNames = Array.from(distinctGrantDisplaysOf(rawGrantRepo.findAll()));
final var givenRelationship = givenSomeTemporaryRelationshipBessler( final var givenRelationship = givenSomeTemporaryRelationshipBessler(
"Anita", "twelfth"); "Anita", "twelfth");
// assertThat(distinctRoleNamesOf(rawRoleRepo.findAll()).size()).as("unexpected number of roles created")
// .isEqualTo(initialRoleNames.length + 3);
// assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()).size()).as("unexpected number of grants created")
// .isEqualTo(initialGrantNames.length + 13);
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {