improve RBAC definition DSL

This commit is contained in:
Michael Hoennig 2024-02-25 13:19:27 +01:00
parent b4d6930fbe
commit 5ac616e425
9 changed files with 135 additions and 122 deletions

View File

@ -16,6 +16,7 @@ import java.util.UUID;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.*; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.*;
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.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@ -56,19 +57,19 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
} }
public static RbacView rbac() { public static RbacView rbac() {
// @formatter:off
return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class) return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class)
.withIdentityView(SQL.query("target.iban || ':' || target.holder")) .withIdentityView(SQL.query("target.iban || ':' || target.holder"))
.withUpdatableColumns("holder", "iban", "bic") .withUpdatableColumns("holder", "iban", "bic")
.createRole(OWNER) .createRole(OWNER, (with) -> {
.withCurrentUserAsOwner() with.owningUser(CREATOR);
.withPermission(ALL) with.incomingSuperRole(GLOBAL, ADMIN);
.withIncomingSuperRole(GLOBAL, ADMIN) with.permission(ALL);
.createSubRole(ADMIN) })
.withPermission(EDIT) .createSubRole(ADMIN, (with) -> {
.createSubRole(REFERRER) with.permission(EDIT);
.withPermission(VIEW) })
.pop(); .createSubRole(REFERRER, (with) -> {
// @formatter:on with.permission(VIEW);
});
} }
} }

View File

@ -14,6 +14,7 @@ import java.util.UUID;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
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.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@ -33,7 +34,6 @@ public class HsOfficeContactEntity implements Stringifyable, HasUuid {
.withProp(Fields.label, HsOfficeContactEntity::getLabel) .withProp(Fields.label, HsOfficeContactEntity::getLabel)
.withProp(Fields.emailAddresses, HsOfficeContactEntity::getEmailAddresses); .withProp(Fields.emailAddresses, HsOfficeContactEntity::getEmailAddresses);
@Id @Id
@GeneratedValue(generator = "UUID") @GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
@ -60,19 +60,19 @@ public class HsOfficeContactEntity implements Stringifyable, HasUuid {
} }
public static RbacView rbac() { public static RbacView rbac() {
// @formatter:off
return rbacViewFor("contact", HsOfficeContactEntity.class) return rbacViewFor("contact", HsOfficeContactEntity.class)
.withIdentityView(RbacView.SQL.query("target.label")) .withIdentityView(RbacView.SQL.query("target.label"))
.withUpdatableColumns("label", "postalAddress", "emailAddresses", "phoneNumbers") .withUpdatableColumns("label", "postalAddress", "emailAddresses", "phoneNumbers")
.createRole(OWNER) .createRole(OWNER, (with) -> {
.withPermission(ALL) with.owningUser(CREATOR);
.withCurrentUserAsOwner() with.incomingSuperRole(GLOBAL, ADMIN);
.withIncomingSuperRole(GLOBAL, ADMIN) with.permission(ALL);
.createSubRole(ADMIN) })
.withPermission(EDIT) .createSubRole(ADMIN, (with) -> {
.createSubRole(REFERRER) with.permission(EDIT);
.withPermission(VIEW) })
.pop(); .createSubRole(REFERRER, (with) -> {
// @formatter:on with.permission(VIEW);
});
} }
} }

View File

@ -4,9 +4,9 @@ import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity; import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.stringify.Stringifyable;
@ -18,9 +18,7 @@ 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.Permission.VIEW;
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.Role.REFERRER;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@ -87,7 +85,7 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
private String defaultPrefix; private String defaultPrefix;
private String getDebitorNumberString() { private String getDebitorNumberString() {
if (partner == null || partner.getPartnerNumber() == null || debitorNumberSuffix == null ) { if (partner == null || partner.getPartnerNumber() == null || debitorNumberSuffix == null) {
return null; return null;
} }
return partner.getPartnerNumber() + String.format("%02d", debitorNumberSuffix); return partner.getPartnerNumber() + String.format("%02d", debitorNumberSuffix);
@ -108,20 +106,19 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
} }
public static RbacView rbac() { public static RbacView rbac() {
// @formatter:off
return rbacViewFor("debitor", HsOfficeDebitorEntity.class) return rbacViewFor("debitor", HsOfficeDebitorEntity.class)
.withIdentityView(RbacView.SQL.query(""" .withIdentityView(RbacView.SQL.query("""
SELECT debitor.uuid, SELECT debitor.uuid,
'D-' || (SELECT partner.partnerNumber 'D-' || (SELECT partner.partnerNumber
FROM hs_office_partner partner FROM hs_office_partner partner
JOIN hs_office_relationship partnerRel JOIN hs_office_relationship partnerRel
ON partnerRel.uuid = partner.partnerRoleUUid AND partnerRel.relType = 'PARTNER' ON partnerRel.uuid = partner.partnerRoleUUid AND partnerRel.relType = 'PARTNER'
JOIN hs_office_relationship debitorRel JOIN hs_office_relationship debitorRel
ON debitorRel.relAnchorUuid = partnerRel.relHolderUuid AND partnerRel.relType = 'ACCOUNTING' ON debitorRel.relAnchorUuid = partnerRel.relHolderUuid AND partnerRel.relType = 'ACCOUNTING'
WHERE debitorRel.uuid = debitor.debitorRelUuid) WHERE debitorRel.uuid = debitor.debitorRelUuid)
|| to_char(debitorNumberSuffix, 'fm00') || to_char(debitorNumberSuffix, 'fm00')
from hs_office_debitor as debitor; from hs_office_debitor as debitor;
""")) """))
.withUpdatableColumns( .withUpdatableColumns(
"debitorRel", "debitorRel",
"billable", "billable",
@ -131,15 +128,15 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
"vatCountryCode", "vatCountryCode",
"vatBusiness", "vatBusiness",
"vatReverseCharge", "vatReverseCharge",
"defaultPrefix" /* TODO: do we want that updatable? */ ) "defaultPrefix" /* TODO: do we want that updatable? */)
.createPermission(custom("new-debitor")).grantedTo("global", ADMIN).pop() .createPermission(custom("new-debitor")).grantedTo("global", ADMIN).pop()
.importProxyEntity("debitorRel", HsOfficeRelationshipEntity.class, .importProxyEntity("debitorRel", HsOfficeRelationshipEntity.class,
fetchedBySql(""" fetchedBySql("""
SELECT * SELECT *
FROM hs_office_relationship AS r FROM hs_office_relationship AS r
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid; WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid;
"""), """),
dependsOnColumn("debitorRelUuid")) dependsOnColumn("debitorRelUuid"))
.createPermission(ALL).grantedTo("debitorRel", OWNER).pop() .createPermission(ALL).grantedTo("debitorRel", OWNER).pop()
.createPermission(EDIT).grantedTo("debitorRel", ADMIN).pop() .createPermission(EDIT).grantedTo("debitorRel", ADMIN).pop()
@ -147,20 +144,20 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
.importEntityAlias("refundBankAccount", HsOfficeBankAccountEntity.class, .importEntityAlias("refundBankAccount", HsOfficeBankAccountEntity.class,
fetchedBySql(""" fetchedBySql("""
SELECT * SELECT *
FROM hs_office_relationship AS r FROM hs_office_relationship AS r
WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid; WHERE r.relType = 'ACCOUNTING' AND r.relHolderUuid = ${REF}.debitorRelUuid;
"""), """),
dependsOnColumn("bankAccountUuid")) dependsOnColumn("bankAccountUuid"))
.toRole("refundBankAccount", ADMIN).grantRole("debitorRel", AGENT) .toRole("refundBankAccount", ADMIN).grantRole("debitorRel", AGENT)
.toRole("debitorRel", AGENT).grantRole("refundBankAccount", REFERRER) .toRole("debitorRel", AGENT).grantRole("refundBankAccount", REFERRER)
.importEntityAlias("partnerRel", HsOfficeRelationshipEntity.class, .importEntityAlias("partnerRel", HsOfficeRelationshipEntity.class,
fetchedBySql(""" fetchedBySql("""
SELECT * SELECT *
FROM hs_office_relationship AS partnerRel FROM hs_office_relationship AS partnerRel
WHERE ${debitorRel}.relAnchorUuid = partnerRel.relHolderUuid; WHERE ${debitorRel}.relAnchorUuid = partnerRel.relHolderUuid;
"""), """),
dependsOnColumn("debitorRelUuid")) dependsOnColumn("debitorRelUuid"))
.toRole("partnerRel", ADMIN).grantRole("debitorRel", ADMIN) .toRole("partnerRel", ADMIN).grantRole("debitorRel", ADMIN)
.toRole("partnerRel", AGENT).grantRole("debitorRel", AGENT) .toRole("partnerRel", AGENT).grantRole("debitorRel", AGENT)
@ -169,6 +166,5 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
.forExampleRole("partnerPerson", ADMIN).wouldBeGrantedTo("partnerRel", ADMIN) .forExampleRole("partnerPerson", ADMIN).wouldBeGrantedTo("partnerRel", ADMIN)
.forExampleRole("operationalPerson", ADMIN).wouldBeGrantedTo("partnerRel", ADMIN) .forExampleRole("operationalPerson", ADMIN).wouldBeGrantedTo("partnerRel", ADMIN)
.forExampleRole("partnerRel", TENANT).wouldBeGrantedTo("partnerPerson", REFERRER); .forExampleRole("partnerRel", TENANT).wouldBeGrantedTo("partnerPerson", REFERRER);
// @formatter:on
} }
} }

View File

@ -14,6 +14,7 @@ import java.util.UUID;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
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.query; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.query;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
@ -64,19 +65,19 @@ public class HsOfficePersonEntity implements HasUuid, Stringifyable {
} }
public static RbacView rbac() { public static RbacView rbac() {
// @formatter:off
return rbacViewFor("person", HsOfficePersonEntity.class) return rbacViewFor("person", HsOfficePersonEntity.class)
.withIdentityView(query("concat(target.tradeName, target.familyName, target.givenName)")) .withIdentityView(query("concat(target.tradeName, target.familyName, target.givenName)"))
.withUpdatableColumns("personType", "tradeName", "givenName", "familyName") .withUpdatableColumns("personType", "tradeName", "givenName", "familyName")
.createRole(OWNER) .createRole(OWNER, (with) -> {
.withPermission(ALL) with.permission(ALL);
.withCurrentUserAsOwner() with.owningUser(CREATOR);
.withIncomingSuperRole(GLOBAL, ADMIN) with.incomingSuperRole(GLOBAL, ADMIN);
.createSubRole(ADMIN) })
.withPermission(EDIT) .createSubRole(ADMIN, (with) -> {
.createSubRole(REFERRER) with.permission(EDIT);
.withPermission(VIEW) })
.pop(); .createSubRole(REFERRER, (with) -> {
// @formatter:on with.permission(VIEW);
});
} }
} }

View File

@ -3,8 +3,8 @@ package net.hostsharing.hsadminng.hs.office.relationship;
import lombok.*; import lombok.*;
import lombok.experimental.FieldNameConstants; import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
@ -16,6 +16,7 @@ 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.GLOBAL; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
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.fetchedBySql; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.fetchedBySql;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
@ -77,13 +78,12 @@ public class HsOfficeRelationshipEntity implements HasUuid, Stringifyable {
} }
public static RbacView rbac() { public static RbacView rbac() {
// @formatter:off
return rbacViewFor("relationship", HsOfficeRelationshipEntity.class) return rbacViewFor("relationship", HsOfficeRelationshipEntity.class)
.withIdentityView(SQL.query(""" .withIdentityView(SQL.query("""
(select idName from hs_office_person_iv p where p.uuid = target.relAnchorUuid) (select idName from hs_office_person_iv p where p.uuid = target.relAnchorUuid)
|| '-with-' || target.relType || '-' || '-with-' || target.relType || '-'
|| (select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid) || (select idName from hs_office_person_iv p where p.uuid = target.relHolderUuid)
""")) """))
.withUpdatableColumns("contactUuid") .withUpdatableColumns("contactUuid")
.importEntityAlias("anchorPerson", HsOfficePersonEntity.class, .importEntityAlias("anchorPerson", HsOfficePersonEntity.class,
fetchedBySql("select * from hs_office_person as p where p.uuid = ${REF}.relAnchorUuid"), fetchedBySql("select * from hs_office_person as p where p.uuid = ${REF}.relAnchorUuid"),
@ -94,23 +94,24 @@ public class HsOfficeRelationshipEntity implements HasUuid, Stringifyable {
.importEntityAlias("contact", HsOfficeContactEntity.class, .importEntityAlias("contact", HsOfficeContactEntity.class,
fetchedBySql("select * from hs_office_contact as c where c.uuid = ${REF}.contactUuid"), fetchedBySql("select * from hs_office_contact as c where c.uuid = ${REF}.contactUuid"),
dependsOnColumn("contactUuid")) dependsOnColumn("contactUuid"))
.createRole(OWNER) .createRole(OWNER, (with) -> {
.withCurrentUserAsOwner() with.owningUser(CREATOR);
.withPermission(ALL) with.incomingSuperRole(GLOBAL, ADMIN);
.withIncomingSuperRole(GLOBAL, ADMIN) with.incomingSuperRole("anchorPerson", ADMIN);
.withIncomingSuperRole("anchorPerson", ADMIN) with.permission(ALL);
.createSubRole(ADMIN) })
.withPermission(EDIT) .createSubRole(ADMIN, (with) -> {
with.permission(EDIT);
})
.createSubRole(AGENT) .createSubRole(AGENT)
.createSubRole(TENANT) .createSubRole(TENANT, (with) -> {
.withPermission(VIEW) with.incomingSuperRole("anchorPerson", ADMIN);
.withIncomingSuperRole("anchorPerson", ADMIN) with.incomingSuperRole("holderPerson", ADMIN);
.withIncomingSuperRole("holderPerson", ADMIN) with.incomingSuperRole("contact", ADMIN);
.withIncomingSuperRole("contact", ADMIN) with.outgoingSubRole("anchorPerson", REFERRER);
.withOutgoingSubRole("anchorPerson", REFERRER) with.outgoingSubRole("holderPerson", REFERRER);
.withOutgoingSubRole("holderPerson", REFERRER) with.outgoingSubRole("contact", REFERRER);
.withOutgoingSubRole("contact", REFERRER) with.permission(VIEW);
.pop(); });
// @formatter:on
} }
} }

View File

@ -1,5 +1,7 @@
package net.hostsharing.hsadminng.rbac.rbacdef; package net.hostsharing.hsadminng.rbac.rbacdef;
import java.util.function.Consumer;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity; import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
@ -37,6 +39,7 @@ public class RbacView {
private SQL identityViewSqlQuery; private SQL identityViewSqlQuery;
private EntityAlias entityAliasProxy; private EntityAlias entityAliasProxy;
private RbacRoleDefinition previousRoleDef;
public static <E extends RbacObject> RbacView rbacViewFor(final String alias, final Class<E> entityClass) { public static <E extends RbacObject> RbacView rbacViewFor(final String alias, final Class<E> entityClass) {
return new RbacView(alias, entityClass); return new RbacView(alias, entityClass);
@ -59,8 +62,26 @@ public class RbacView {
return this; return this;
} }
public RbacRoleDefinition createRole(final Role role) { public RbacView createRole(final Role role, final Consumer<RbacRoleDefinition> with) {
return findRbacRole(entityAlias, role).toCreate(); final RbacRoleDefinition newRoleDef = findRbacRole(entityAlias, role).toCreate();
with.accept(newRoleDef);
previousRoleDef = newRoleDef;
return this;
}
public RbacView createSubRole(final Role role) {
final RbacRoleDefinition newRoleDef = findRbacRole(entityAlias, role).toCreate();
new RbacGrantDefinition(newRoleDef, previousRoleDef).toCreate();
previousRoleDef = newRoleDef;
return this;
}
public RbacView createSubRole(final Role role, final Consumer<RbacRoleDefinition> with) {
final RbacRoleDefinition newRoleDef = findRbacRole(entityAlias, role).toCreate();
new RbacGrantDefinition(newRoleDef, previousRoleDef).toCreate();
with.accept(newRoleDef);
previousRoleDef = newRoleDef;
return this;
} }
public RbacPermissionDefinition createPermission(final Permission permission) { public RbacPermissionDefinition createPermission(final Permission permission) {
@ -143,8 +164,8 @@ public class RbacView {
} }
private RbacGrantDefinition grantRoleToCurrentUser(final RbacRoleDefinition roleDefinition) { private RbacGrantDefinition grantRoleToUser(final RbacRoleDefinition roleDefinition, final RbacUserReference user) {
return new RbacGrantDefinition(roleDefinition, currentUser()).toCreate(); return new RbacGrantDefinition(roleDefinition, user).toCreate();
} }
private RbacGrantDefinition grantPermissionToRole(final RbacPermissionDefinition permDef , final RbacRoleDefinition roleDef) { private RbacGrantDefinition grantPermissionToRole(final RbacPermissionDefinition permDef , final RbacRoleDefinition roleDef) {
@ -325,46 +346,36 @@ public class RbacView {
return this; return this;
} }
public RbacRoleDefinition withCurrentUserAsOwner() { public RbacRoleDefinition owningUser(final RbacUserReference.UserRole userRole) {
addGrant(grantRoleToCurrentUser(this)); addGrant(grantRoleToUser(this, findUserRef(userRole)));
return this; return this;
} }
public RbacRoleDefinition withPermission(final Permission permission) { public RbacRoleDefinition permission(final Permission permission) {
addGrant(grantPermissionToRole( createPermission(entityAlias, permission) , this)); addGrant(grantPermissionToRole( createPermission(entityAlias, permission) , this));
return this; return this;
} }
public RbacRoleDefinition withIncomingSuperRole(final String entityAlias, final Role role) { public RbacRoleDefinition incomingSuperRole(final String entityAlias, final Role role) {
final var incomingSuperRole = findRbacRole(entityAlias, role); final var incomingSuperRole = findRbacRole(entityAlias, role);
addGrant(grantSubRoleToSuperRole(this, incomingSuperRole)); addGrant(grantSubRoleToSuperRole(this, incomingSuperRole));
return this; return this;
} }
public RbacRoleDefinition withOutgoingSubRole(final String entityAlias, final Role role) { public RbacRoleDefinition outgoingSubRole(final String entityAlias, final Role role) {
final var outgoingSubRole = findRbacRole(entityAlias, role); final var outgoingSubRole = findRbacRole(entityAlias, role);
addGrant(grantSubRoleToSuperRole(outgoingSubRole, this)); addGrant(grantSubRoleToSuperRole(outgoingSubRole, this));
return this; return this;
} }
public RbacRoleDefinition createSubRole(final Role role) {
final var roleDef = findRbacRole(entityAlias, role).toCreate();
new RbacGrantDefinition(roleDef, this).toCreate();
return roleDef;
}
public RbacView pop() {
return RbacView.this;
}
@Override @Override
public String toString() { public String toString() {
return "role:" + entityAlias.aliasName + role; return "role:" + entityAlias.aliasName + role;
} }
} }
public RbacUserReference currentUser() { public RbacUserReference findUserRef(final RbacUserReference.UserRole userRole) {
return userDefs.stream().filter(u -> u.role == CREATOR).findFirst().orElseThrow(); return userDefs.stream().filter(u -> u.role == userRole).findFirst().orElseThrow();
} }
@EqualsAndHashCode @EqualsAndHashCode

View File

@ -22,6 +22,7 @@ public class RbacViewMermaidFlowchart {
%%{init:{'flowchart':{'htmlLabels':false}}}%% %%{init:{'flowchart':{'htmlLabels':false}}}%%
flowchart TB flowchart TB
"""); """);
flowchart.writeLn();
renderEntitySubgraphs(); renderEntitySubgraphs();
renderGrants(); renderGrants();
} }

View File

@ -11,7 +11,9 @@ import jakarta.persistence.*;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.GLOBAL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.*; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.ALL;
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.VIEW;
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.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
@ -36,19 +38,19 @@ public class TestCustomerEntity implements RbacObject {
public static RbacView rbac() { public static RbacView rbac() {
// @formatter:off
return rbacViewFor("contact", TestCustomerEntity.class) return rbacViewFor("contact", TestCustomerEntity.class)
.withIdentityView(RbacView.SQL.query("target.prefix")) .withIdentityView(RbacView.SQL.query("target.prefix"))
.withUpdatableColumns("reference", "prefix", "adminUserName") .withUpdatableColumns("reference", "prefix", "adminUserName")
.createRole(OWNER) .createRole(OWNER, (with) -> {
.withPermission(ALL) with.owningUser(CREATOR);
.withCurrentUserAsOwner() with.incomingSuperRole(GLOBAL, ADMIN);
.withIncomingSuperRole(GLOBAL, ADMIN) with.permission(ALL);
.createSubRole(ADMIN) })
.withPermission(RbacView.Permission.custom("add-package")) .createSubRole(ADMIN, (with) -> {
.createSubRole(TENANT) with.permission(RbacView.Permission.custom("add-package"));
.withPermission(VIEW) })
.pop(); .createSubRole(TENANT, (with) -> {
// @formatter:on with.permission(VIEW);
});
} }
} }

View File

@ -35,11 +35,11 @@ class TestCustomerEntityTest {
end end
end end
role:contact:owner ==> perm:contact:*
role:contact:owner ==> perm:contact:*
user:creator ==> role:contact:owner user:creator ==> role:contact:owner
role:global:admin ==> role:contact:owner role:global:admin ==> role:contact:owner
role:global:admin ==> role:contact:owner role:global:admin ==> role:contact:owner
role:contact:owner ==> perm:contact:*
role:contact:owner ==> perm:contact:*
role:contact:owner ==> role:contact:admin role:contact:owner ==> role:contact:admin
role:contact:admin ==> perm:contact:add-package role:contact:admin ==> perm:contact:add-package
role:contact:admin ==> perm:contact:add-package role:contact:admin ==> perm:contact:add-package