WIP: rbac-generator-with-conditional-grants
This commit is contained in:
parent
6346dff3ef
commit
4f25bf1496
@ -104,18 +104,16 @@ public class HsOfficeRelationEntity implements RbacObject, Stringifyable {
|
||||
.createRole(OWNER, (with) -> {
|
||||
with.owningUser(CREATOR);
|
||||
with.incomingSuperRole(GLOBAL, ADMIN);
|
||||
// TODO: if type=REPRESENTATIIVE
|
||||
// with.incomingSuperRole("holderPerson", ADMIN);
|
||||
with.incomingSuperRole("holderPerson", ADMIN).where("${REF}.type = 'REPRESENTATIVE'");
|
||||
with.permission(DELETE);
|
||||
})
|
||||
.createSubRole(ADMIN, (with) -> {
|
||||
with.incomingSuperRole("anchorPerson", ADMIN);
|
||||
// TODO: if type=REPRESENTATIIVE
|
||||
// with.outgoingSuperRole("anchorPerson", OWNER);
|
||||
with.incomingSuperRole("anchorPerson", ADMIN).where("${REF}.type <> 'REPRESENTATIVE'");
|
||||
with.outgoingSubRole("anchorPerson", OWNER).where("${REF}.type = 'REPRESENTATIVE'");
|
||||
with.permission(UPDATE);
|
||||
})
|
||||
.createSubRole(AGENT, (with) -> {
|
||||
with.incomingSuperRole("holderPerson", ADMIN);
|
||||
with.incomingSuperRole("holderPerson", ADMIN).where("${REF}.type <> 'REPRESENTATIVE'");
|
||||
})
|
||||
.createSubRole(TENANT, (with) -> {
|
||||
with.incomingSuperRole("contact", ADMIN);
|
||||
|
@ -496,10 +496,13 @@ public class RbacView {
|
||||
private final RbacPermissionDefinition permDef;
|
||||
private boolean assumed = true;
|
||||
private boolean toCreate = false;
|
||||
private String sqlWhere;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final var arrow = isAssumed() ? " --> " : " -- // --> ";
|
||||
final var arrow = isConditional()
|
||||
? (isAssumed() ? " -- ?? --> " : " -- ?//? --> ")
|
||||
: (isAssumed() ? " --> " : " -- // --> ");
|
||||
return switch (grantType()) {
|
||||
case ROLE_TO_USER -> userDef.toString() + arrow + subRoleDef.toString();
|
||||
case ROLE_TO_ROLE -> superRoleDef + arrow + subRoleDef;
|
||||
@ -546,6 +549,10 @@ public class RbacView {
|
||||
return assumed;
|
||||
}
|
||||
|
||||
boolean isConditional() {
|
||||
return sqlWhere != null;
|
||||
}
|
||||
|
||||
boolean isToCreate() {
|
||||
return toCreate;
|
||||
}
|
||||
@ -567,8 +574,14 @@ public class RbacView {
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
public void unassumed() {
|
||||
public RbacGrantDefinition unassumed() {
|
||||
this.assumed = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RbacGrantDefinition where(final String sqlWhere) {
|
||||
this.sqlWhere = sqlWhere;
|
||||
return this;
|
||||
}
|
||||
|
||||
public enum GrantType {
|
||||
|
@ -109,7 +109,9 @@ public class RbacViewMermaidFlowchartGenerator {
|
||||
|
||||
private String grantDef(final RbacView.RbacGrantDefinition grant) {
|
||||
final var arrow = (grant.isToCreate() ? " ==>" : " -.->")
|
||||
+ (grant.isAssumed() ? " " : "|XX| ");
|
||||
+ (grant.isConditional()
|
||||
? (grant.isAssumed() ? " |??| " : "|?XX?| ")
|
||||
: (grant.isAssumed() ? " " : "|XX| "));
|
||||
return switch (grant.grantType()) {
|
||||
case ROLE_TO_USER ->
|
||||
// TODO: other user types not implemented yet
|
||||
|
@ -82,10 +82,12 @@ role:global:ADMIN -.-> role:contact:OWNER
|
||||
role:contact:OWNER -.-> role:contact:ADMIN
|
||||
role:contact:ADMIN -.-> role:contact:REFERRER
|
||||
role:global:ADMIN ==> role:relation:OWNER
|
||||
role:holderPerson:ADMIN ==> |??| role:relation:OWNER
|
||||
role:relation:OWNER ==> role:relation:ADMIN
|
||||
role:anchorPerson:ADMIN ==> role:relation:ADMIN
|
||||
role:anchorPerson:ADMIN ==> |??| role:relation:ADMIN
|
||||
role:relation:ADMIN ==> |??| role:anchorPerson:OWNER
|
||||
role:relation:ADMIN ==> role:relation:AGENT
|
||||
role:holderPerson:ADMIN ==> role:relation:AGENT
|
||||
role:holderPerson:ADMIN ==> |??| role:relation:AGENT
|
||||
role:relation:AGENT ==> role:relation:TENANT
|
||||
role:contact:ADMIN ==> role:relation:TENANT
|
||||
role:relation:TENANT ==> role:anchorPerson:REFERRER
|
||||
|
@ -57,16 +57,12 @@ begin
|
||||
perform createRoleWithGrants(
|
||||
hsOfficeRelationADMIN(NEW),
|
||||
permissions => array['UPDATE'],
|
||||
incomingSuperRoles => array[
|
||||
hsOfficePersonADMIN(newAnchorPerson),
|
||||
hsOfficeRelationOWNER(NEW)]
|
||||
incomingSuperRoles => array[hsOfficeRelationOWNER(NEW)]
|
||||
);
|
||||
|
||||
perform createRoleWithGrants(
|
||||
hsOfficeRelationAGENT(NEW),
|
||||
incomingSuperRoles => array[
|
||||
hsOfficePersonADMIN(newHolderPerson),
|
||||
hsOfficeRelationADMIN(NEW)]
|
||||
incomingSuperRoles => array[hsOfficeRelationADMIN(NEW)]
|
||||
);
|
||||
|
||||
perform createRoleWithGrants(
|
||||
@ -81,6 +77,19 @@ begin
|
||||
hsOfficePersonREFERRER(newHolderPerson)]
|
||||
);
|
||||
|
||||
if NEW.type <> 'REPRESENTATIVE' then
|
||||
call grantRoleToRole(hsOfficeRelationADMIN(NEW), hsOfficePersonADMIN(newAnchorPerson));
|
||||
end if;
|
||||
if NEW.type <> 'REPRESENTATIVE' then
|
||||
call grantRoleToRole(hsOfficeRelationAGENT(NEW), hsOfficePersonADMIN(newHolderPerson));
|
||||
end if;
|
||||
if NEW.type = 'REPRESENTATIVE' then
|
||||
call grantRoleToRole(hsOfficePersonOWNER(newAnchorPerson), hsOfficeRelationADMIN(NEW));
|
||||
end if;
|
||||
if NEW.type = 'REPRESENTATIVE' then
|
||||
call grantRoleToRole(hsOfficeRelationOWNER(NEW), hsOfficePersonADMIN(newHolderPerson));
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
end; $$;
|
||||
|
||||
@ -117,48 +126,12 @@ create or replace procedure updateRbacRulesForHsOfficeRelation(
|
||||
NEW hs_office_relation
|
||||
)
|
||||
language plpgsql as $$
|
||||
|
||||
declare
|
||||
oldHolderPerson hs_office_person;
|
||||
newHolderPerson hs_office_person;
|
||||
oldAnchorPerson hs_office_person;
|
||||
newAnchorPerson hs_office_person;
|
||||
oldContact hs_office_contact;
|
||||
newContact hs_office_contact;
|
||||
|
||||
begin
|
||||
call enterTriggerForObjectUuid(NEW.uuid);
|
||||
|
||||
SELECT * FROM hs_office_person WHERE uuid = OLD.holderUuid INTO oldHolderPerson;
|
||||
assert oldHolderPerson.uuid is not null, format('oldHolderPerson must not be null for OLD.holderUuid = %s', OLD.holderUuid);
|
||||
|
||||
SELECT * FROM hs_office_person WHERE uuid = NEW.holderUuid INTO newHolderPerson;
|
||||
assert newHolderPerson.uuid is not null, format('newHolderPerson must not be null for NEW.holderUuid = %s', NEW.holderUuid);
|
||||
|
||||
SELECT * FROM hs_office_person WHERE uuid = OLD.anchorUuid INTO oldAnchorPerson;
|
||||
assert oldAnchorPerson.uuid is not null, format('oldAnchorPerson must not be null for OLD.anchorUuid = %s', OLD.anchorUuid);
|
||||
|
||||
SELECT * FROM hs_office_person WHERE uuid = NEW.anchorUuid INTO newAnchorPerson;
|
||||
assert newAnchorPerson.uuid is not null, format('newAnchorPerson must not be null for NEW.anchorUuid = %s', NEW.anchorUuid);
|
||||
|
||||
SELECT * FROM hs_office_contact WHERE uuid = OLD.contactUuid INTO oldContact;
|
||||
assert oldContact.uuid is not null, format('oldContact must not be null for OLD.contactUuid = %s', OLD.contactUuid);
|
||||
|
||||
SELECT * FROM hs_office_contact WHERE uuid = NEW.contactUuid INTO newContact;
|
||||
assert newContact.uuid is not null, format('newContact must not be null for NEW.contactUuid = %s', NEW.contactUuid);
|
||||
|
||||
|
||||
if NEW.contactUuid <> OLD.contactUuid then
|
||||
|
||||
call revokeRoleFromRole(hsOfficeRelationTENANT(OLD), hsOfficeContactADMIN(oldContact));
|
||||
call grantRoleToRole(hsOfficeRelationTENANT(NEW), hsOfficeContactADMIN(newContact));
|
||||
|
||||
call revokeRoleFromRole(hsOfficeContactREFERRER(oldContact), hsOfficeRelationTENANT(OLD));
|
||||
call grantRoleToRole(hsOfficeContactREFERRER(newContact), hsOfficeRelationTENANT(NEW));
|
||||
|
||||
if NEW.contactUuid is distinct from OLD.contactUuid then
|
||||
delete from rbacgrants g where g.grantedbytriggerof = OLD.uuid;
|
||||
call buildRbacSystemForHsOfficeRelation(NEW);
|
||||
end if;
|
||||
|
||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||
end; $$;
|
||||
|
||||
/*
|
||||
|
@ -103,6 +103,69 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
|
||||
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
|
||||
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll());
|
||||
|
||||
// when
|
||||
attempt(em, () -> {
|
||||
final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Bessler").stream()
|
||||
.filter(p -> p.getPersonType() == UNINCORPORATED_FIRM)
|
||||
.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 newRelation = HsOfficeRelationEntity.builder()
|
||||
.anchor(givenAnchorPerson)
|
||||
.holder(givenHolderPerson)
|
||||
.type(HsOfficeRelationType.SUBSCRIBER)
|
||||
.mark("dummy")
|
||||
.contact(givenContact)
|
||||
.build();
|
||||
return toCleanup(relationRepo.save(newRelation));
|
||||
});
|
||||
|
||||
// then
|
||||
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(Array.from(
|
||||
initialRoleNames,
|
||||
"hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:OWNER",
|
||||
"hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:ADMIN",
|
||||
"hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:AGENT",
|
||||
"hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:TENANT"));
|
||||
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
|
||||
initialGrantNames,
|
||||
// TODO: this grant should only be created for DEBITOR-Relationships, thus the RBAC DSL needs to support conditional grants
|
||||
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:INSERT>hs_office_sepamandate to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:ADMIN by system and assume }",
|
||||
|
||||
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:DELETE to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:OWNER by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:OWNER to role:global#global:ADMIN by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:OWNER to user:superuser-alex@hostsharing.net by hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:OWNER and assume }",
|
||||
|
||||
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:UPDATE to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:ADMIN by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:ADMIN to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:OWNER by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:ADMIN to role:hs_office_person#ErbenBesslerMelBessler:ADMIN by system and assume }",
|
||||
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:AGENT to role:hs_office_person#BesslerBert:ADMIN by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:AGENT to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:ADMIN by system and assume }",
|
||||
|
||||
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:SELECT to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:TENANT by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:TENANT to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:AGENT by system and assume }",
|
||||
"{ grant role:hs_office_person#BesslerBert:REFERRER to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:TENANT by system and assume }",
|
||||
"{ grant role:hs_office_person#ErbenBesslerMelBessler:REFERRER to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:TENANT by system and assume }",
|
||||
"{ grant role:hs_office_contact#fourthcontact:REFERRER to role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:TENANT by system and assume }",
|
||||
|
||||
// SUBSCRIBER holder person -> (represented) anchor person
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-SUBSCRIBER-BesslerBert:TENANT to role:hs_office_contact#fourthcontact:ADMIN by system and assume }",
|
||||
|
||||
null)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createsAndGrantsRolesForTypeRepresentative() {
|
||||
// given
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
|
||||
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll());
|
||||
|
||||
// when
|
||||
attempt(em, () -> {
|
||||
final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Bessler").stream()
|
||||
@ -140,9 +203,9 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
|
||||
|
||||
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:UPDATE to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:OWNER by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN to role:hs_office_person#ErbenBesslerMelBessler:ADMIN by system and assume }",
|
||||
"{ grant role:hs_office_person#ErbenBesslerMelBessler:OWNER to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN by system and assume }",
|
||||
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:AGENT to role:hs_office_person#BesslerBert:ADMIN by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:OWNER to role:hs_office_person#BesslerBert:ADMIN by system and assume }",
|
||||
"{ grant role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:AGENT to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:ADMIN by system and assume }",
|
||||
|
||||
"{ grant perm:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:SELECT to role:hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert:TENANT by system and assume }",
|
||||
|
Loading…
Reference in New Issue
Block a user