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
9 changed files with 135 additions and 122 deletions
Showing only changes of commit 5ac616e425 - Show all commits

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;
@ -108,7 +106,6 @@ 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,
@ -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,7 +78,6 @@ 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)
@ -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