fix indrirect permission by indirect foreign key
This commit is contained in:
parent
78ecf98913
commit
e6ef5b59c7
@ -21,6 +21,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
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.Nullable.NOT_NULL;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NULLABLE;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Nullable.NULLABLE;
|
||||||
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.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
@ -165,8 +166,7 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
FROM hs_office_bankaccount AS b
|
FROM hs_office_bankaccount AS b
|
||||||
WHERE b.uuid = ${REF}.refundBankAccountUuid
|
WHERE b.uuid = ${REF}.refundBankAccountUuid
|
||||||
"""),
|
"""),
|
||||||
NULLABLE
|
NULLABLE)
|
||||||
)
|
|
||||||
.toRole("refundBankAccount", ADMIN).grantRole("debitorRel", AGENT)
|
.toRole("refundBankAccount", ADMIN).grantRole("debitorRel", AGENT)
|
||||||
.toRole("debitorRel", AGENT).grantRole("refundBankAccount", REFERRER)
|
.toRole("debitorRel", AGENT).grantRole("refundBankAccount", REFERRER)
|
||||||
|
|
||||||
@ -179,8 +179,8 @@ public class HsOfficeDebitorEntity implements HasUuid, Stringifyable {
|
|||||||
ON debitorRel.type = 'DEBITOR' AND debitorRel.anchorUuid = partnerRel.holderUuid
|
ON debitorRel.type = 'DEBITOR' AND debitorRel.anchorUuid = partnerRel.holderUuid
|
||||||
WHERE partnerRel.type = 'PARTNER'
|
WHERE partnerRel.type = 'PARTNER'
|
||||||
AND ${REF}.debitorRelUuid = debitorRel.uuid
|
AND ${REF}.debitorRelUuid = debitorRel.uuid
|
||||||
""")
|
"""),
|
||||||
)
|
NOT_NULL)
|
||||||
.toRole("partnerRel", ADMIN).grantRole("debitorRel", ADMIN)
|
.toRole("partnerRel", ADMIN).grantRole("debitorRel", ADMIN)
|
||||||
.toRole("partnerRel", AGENT).grantRole("debitorRel", AGENT)
|
.toRole("partnerRel", AGENT).grantRole("debitorRel", AGENT)
|
||||||
.toRole("debitorRel", AGENT).grantRole("partnerRel", TENANT)
|
.toRole("debitorRel", AGENT).grantRole("partnerRel", TENANT)
|
||||||
|
@ -20,6 +20,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
||||||
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.Nullable.NOT_NULL;
|
||||||
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.SELECT;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||||
@ -135,7 +136,8 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
|
|||||||
FROM hs_office_partner AS p
|
FROM hs_office_partner AS p
|
||||||
JOIN hs_office_relation AS r ON r.uuid = p.partnerRelUuid
|
JOIN hs_office_relation AS r ON r.uuid = p.partnerRelUuid
|
||||||
WHERE p.uuid = ${REF}.partnerUuid
|
WHERE p.uuid = ${REF}.partnerUuid
|
||||||
"""))
|
"""),
|
||||||
|
NOT_NULL)
|
||||||
.toRole("partnerRel", ADMIN).grantPermission(INSERT)
|
.toRole("partnerRel", ADMIN).grantPermission(INSERT)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
|
@ -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.Nullable.NOT_NULL;
|
||||||
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.RbacUserReference.UserRole.CREATOR;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
@ -90,16 +91,16 @@ public class HsOfficeRelationEntity implements HasUuid, Stringifyable {
|
|||||||
.withUpdatableColumns("contactUuid")
|
.withUpdatableColumns("contactUuid")
|
||||||
.importEntityAlias("anchorPerson", HsOfficePersonEntity.class,
|
.importEntityAlias("anchorPerson", HsOfficePersonEntity.class,
|
||||||
dependsOnColumn("anchorUuid"),
|
dependsOnColumn("anchorUuid"),
|
||||||
fetchedBySql("select * from hs_office_person as p where p.uuid = ${REF}.anchorUuid")
|
fetchedBySql("select * from hs_office_person as p where p.uuid = ${REF}.anchorUuid"),
|
||||||
)
|
NOT_NULL)
|
||||||
.importEntityAlias("holderPerson", HsOfficePersonEntity.class,
|
.importEntityAlias("holderPerson", HsOfficePersonEntity.class,
|
||||||
dependsOnColumn("holderUuid"),
|
dependsOnColumn("holderUuid"),
|
||||||
fetchedBySql("select * from hs_office_person as p where p.uuid = ${REF}.holderUuid")
|
fetchedBySql("select * from hs_office_person as p where p.uuid = ${REF}.holderUuid"),
|
||||||
)
|
NOT_NULL)
|
||||||
.importEntityAlias("contact", HsOfficeContactEntity.class,
|
.importEntityAlias("contact", HsOfficeContactEntity.class,
|
||||||
dependsOnColumn("contactUuid"),
|
dependsOnColumn("contactUuid"),
|
||||||
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"),
|
||||||
)
|
NOT_NULL)
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
with.owningUser(CREATOR);
|
with.owningUser(CREATOR);
|
||||||
with.incomingSuperRole(GLOBAL, ADMIN);
|
with.incomingSuperRole(GLOBAL, ADMIN);
|
||||||
|
@ -21,6 +21,7 @@ import java.util.UUID;
|
|||||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.*;
|
||||||
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.Nullable.NOT_NULL;
|
||||||
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.RbacUserReference.UserRole.CREATOR;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
@ -110,12 +111,12 @@ public class HsOfficeSepaMandateEntity implements Stringifyable, HasUuid {
|
|||||||
FROM hs_office_relation debitorRel
|
FROM hs_office_relation debitorRel
|
||||||
JOIN hs_office_debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid
|
JOIN hs_office_debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid
|
||||||
WHERE debitor.uuid = ${REF}.debitorUuid
|
WHERE debitor.uuid = ${REF}.debitorUuid
|
||||||
""")
|
"""),
|
||||||
)
|
NOT_NULL)
|
||||||
.importEntityAlias("bankAccount", HsOfficeBankAccountEntity.class,
|
.importEntityAlias("bankAccount", HsOfficeBankAccountEntity.class,
|
||||||
dependsOnColumn("bankAccountUuid"),
|
dependsOnColumn("bankAccountUuid"),
|
||||||
autoFetched()
|
autoFetched(),
|
||||||
)
|
NOT_NULL)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
with.owningUser(CREATOR);
|
with.owningUser(CREATOR);
|
||||||
|
@ -113,8 +113,17 @@ public class InsertTriggerGenerator {
|
|||||||
"invalid global role for INSERT permission: " + g.getSuperRoleDef().getRole());
|
"invalid global role for INSERT permission: " + g.getSuperRoleDef().getRole());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
final var superRoleEntityAlias = g.getSuperRoleDef().getEntityAlias();
|
||||||
|
|
||||||
|
// TODO: Maybe this should depend on the indirection degree of the fetchSql?
|
||||||
|
// Maybe we need a separate fetchedBy method for all the simple, direct cases?
|
||||||
|
if (superRoleEntityAlias.fetchSql().sql.contains("JOIN ")) {
|
||||||
|
generateInsertPermissionTriggerAllowByRoleOfIndirectForeignKey(plPgSql, g);
|
||||||
} else {
|
} else {
|
||||||
generateInsertPermissionTriggerAllowByRoleOfDirectForeignKey(plPgSql, g);
|
generateInsertPermissionTriggerAllowByRoleOfDirectForeignKey(plPgSql, g);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() -> {
|
() -> {
|
||||||
@ -149,6 +158,50 @@ public class InsertTriggerGenerator {
|
|||||||
with("referenceColumn", g.getSuperRoleDef().getEntityAlias().dependsOnColumName()));
|
with("referenceColumn", g.getSuperRoleDef().getEntityAlias().dependsOnColumName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateInsertPermissionTriggerAllowByRoleOfIndirectForeignKey(
|
||||||
|
final StringWriter plPgSql,
|
||||||
|
final RbacView.RbacGrantDefinition g) {
|
||||||
|
plPgSql.writeLn("""
|
||||||
|
/**
|
||||||
|
Checks if the user or assumed roles are allowed to insert a row to ${rawSubTable},
|
||||||
|
where the check is performed by an indirect role.
|
||||||
|
|
||||||
|
An indirect role is a role FIXME.
|
||||||
|
*/
|
||||||
|
create or replace function ${rawSubTable}_insert_permission_missing_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql as $$
|
||||||
|
begin
|
||||||
|
if ( not hasInsertPermission(
|
||||||
|
( SELECT ${varName}.uuid FROM
|
||||||
|
""",
|
||||||
|
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()),
|
||||||
|
with("varName", g.getSuperRoleDef().getEntityAlias().aliasName()));
|
||||||
|
plPgSql.indented(3, () -> {
|
||||||
|
plPgSql.writeLn(
|
||||||
|
"(" + g.getSuperRoleDef().getEntityAlias().fetchSql().sql + ") AS ${varName}",
|
||||||
|
with("varName", g.getSuperRoleDef().getEntityAlias().aliasName()),
|
||||||
|
with("ref", NEW.name()));
|
||||||
|
});
|
||||||
|
plPgSql.writeLn("""
|
||||||
|
|
||||||
|
), 'INSERT', '${rawSubTable}') ) then
|
||||||
|
raise exception
|
||||||
|
'[403] insert into ${rawSubTable} not allowed for current subjects % (%)',
|
||||||
|
currentSubjects(), currentSubjectsUuids();
|
||||||
|
end if;
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
create trigger ${rawSubTable}_insert_permission_check_tg
|
||||||
|
before insert on ${rawSubTable}
|
||||||
|
for each row
|
||||||
|
execute procedure ${rawSubTable}_insert_permission_missing_tf();
|
||||||
|
|
||||||
|
""",
|
||||||
|
with("rawSubTable", rbacDef.getRootEntityAlias().getRawTableName()));
|
||||||
|
}
|
||||||
|
|
||||||
private void generateInsertPermissionTriggerAllowOnlyGlobalAdmin(final StringWriter plPgSql) {
|
private void generateInsertPermissionTriggerAllowOnlyGlobalAdmin(final StringWriter plPgSql) {
|
||||||
plPgSql.writeLn("""
|
plPgSql.writeLn("""
|
||||||
/**
|
/**
|
||||||
|
@ -66,6 +66,21 @@ public class RbacView {
|
|||||||
private EntityAlias rootEntityAliasProxy;
|
private EntityAlias rootEntityAliasProxy;
|
||||||
private RbacRoleDefinition previousRoleDef;
|
private RbacRoleDefinition previousRoleDef;
|
||||||
|
|
||||||
|
/** Crates an RBAC definition template for the given entity class and defining the given alias.
|
||||||
|
*
|
||||||
|
* @param alias
|
||||||
|
* an alias name for this entity/table, which can be used in further grants
|
||||||
|
*
|
||||||
|
* @param entityClass
|
||||||
|
* the Java class for which this RBAC definition is to be defined
|
||||||
|
* (the class to which the calling method belongs)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the newly created RBAC definition template
|
||||||
|
*
|
||||||
|
* @param <E>
|
||||||
|
* a JPA entity class extending RbacObject
|
||||||
|
*/
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -77,22 +92,71 @@ public class RbacView {
|
|||||||
entityAliases.put("global", new EntityAlias("global"));
|
entityAliases.put("global", new EntityAlias("global"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies, which columns of the restricted view are updatable at all.
|
||||||
|
*
|
||||||
|
* @param columnNames
|
||||||
|
* A list of the updatable columns.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the `this` instance itself to allow chained calls.
|
||||||
|
*/
|
||||||
public RbacView withUpdatableColumns(final String... columnNames) {
|
public RbacView withUpdatableColumns(final String... columnNames) {
|
||||||
Collections.addAll(updatableColumns, columnNames);
|
Collections.addAll(updatableColumns, columnNames);
|
||||||
verifyVersionColumnExists();
|
verifyVersionColumnExists();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Specifies the SQL query which creates the identity view for this entity.
|
||||||
|
*
|
||||||
|
* <p>An identity view is a view which maps an objectUuid to an idName.
|
||||||
|
* The idName should be a human-readable representation of the row, but as short as possible.
|
||||||
|
* The idName must only consist of letters (A-Z, a-z), digits (0-9), dash (-), dot (.) and unserscore '_'.
|
||||||
|
* It's used to create the object-specific-role-names like test_customer#abc.admin - here 'abc' is the idName.
|
||||||
|
* The idName not necessarily unique in a table, but it should be avoided.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param sqlExpression
|
||||||
|
* Either specify an SQL projection (the part between SELECT and FROM), e.g. `SQL.projection("columnName")
|
||||||
|
* or the whole SELECT query returning the uuid and idName columns,
|
||||||
|
* e.g. `SQL.query("SELECT ... AS uuid, ... AS idName FROM ... JOIN ...").
|
||||||
|
* Only add really important columns, just enough to create a short human-readable representation.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the `this` instance itself to allow chained calls.
|
||||||
|
*/
|
||||||
public RbacView withIdentityView(final SQL sqlExpression) {
|
public RbacView withIdentityView(final SQL sqlExpression) {
|
||||||
this.identityViewSqlQuery = sqlExpression;
|
this.identityViewSqlQuery = sqlExpression;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies a ORDER BY clause for the generated restricted view.
|
||||||
|
*
|
||||||
|
* <p>A restricted view is generated, no matter if the order was specified or not.</p>
|
||||||
|
*
|
||||||
|
* @param orderBySqlExpression
|
||||||
|
* That's the part behind `ORDER BY`, e.g. `SQL.expression("prefix").
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the `this` instance itself to allow chained calls.
|
||||||
|
*/
|
||||||
public RbacView withRestrictedViewOrderBy(final SQL orderBySqlExpression) {
|
public RbacView withRestrictedViewOrderBy(final SQL orderBySqlExpression) {
|
||||||
this.orderBySqlExpression = orderBySqlExpression;
|
this.orderBySqlExpression = orderBySqlExpression;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that the given role (OWNER, ADMIN, ...) is to be created for new/updated roles in this table.
|
||||||
|
*
|
||||||
|
* @param role
|
||||||
|
* OWNER, ADMIN, AGENT etc.
|
||||||
|
* @param with
|
||||||
|
* a lambda which receives the created role to create grants and permissions to and from the newly created role,
|
||||||
|
* e.g. the owning user, incoming superroles, outgoing subroles
|
||||||
|
* @return
|
||||||
|
* the `this` instance itself to allow chained calls.
|
||||||
|
*/
|
||||||
public RbacView createRole(final Role role, final Consumer<RbacRoleDefinition> with) {
|
public RbacView createRole(final Role role, final Consumer<RbacRoleDefinition> with) {
|
||||||
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
||||||
with.accept(newRoleDef);
|
with.accept(newRoleDef);
|
||||||
@ -100,6 +164,15 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that the given role (OWNER, ADMIN, ...) is to be created for new/updated roles in this table,
|
||||||
|
* which is becomes sub-role of the previously created role.
|
||||||
|
*
|
||||||
|
* @param role
|
||||||
|
* OWNER, ADMIN, AGENT etc.
|
||||||
|
* @return
|
||||||
|
* the `this` instance itself to allow chained calls.
|
||||||
|
*/
|
||||||
public RbacView createSubRole(final Role role) {
|
public RbacView createSubRole(final Role role) {
|
||||||
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
||||||
findOrCreateGrantDef(newRoleDef, previousRoleDef).toCreate();
|
findOrCreateGrantDef(newRoleDef, previousRoleDef).toCreate();
|
||||||
@ -107,6 +180,19 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that the given role (OWNER, ADMIN, ...) is to be created for new/updated roles in this table,
|
||||||
|
* which is becomes sub-role of the previously created role.
|
||||||
|
*
|
||||||
|
* @param role
|
||||||
|
* OWNER, ADMIN, AGENT etc.
|
||||||
|
* @param with
|
||||||
|
* a lambda which receives the created role to create grants and permissions to and from the newly created role,
|
||||||
|
* e.g. the owning user, incoming superroles, outgoing subroles
|
||||||
|
* @return
|
||||||
|
* the `this` instance itself to allow chained calls.
|
||||||
|
*/
|
||||||
public RbacView createSubRole(final Role role, final Consumer<RbacRoleDefinition> with) {
|
public RbacView createSubRole(final Role role, final Consumer<RbacRoleDefinition> with) {
|
||||||
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
final RbacRoleDefinition newRoleDef = findRbacRole(rootEntityAlias, role).toCreate();
|
||||||
findOrCreateGrantDef(newRoleDef, previousRoleDef).toCreate();
|
findOrCreateGrantDef(newRoleDef, previousRoleDef).toCreate();
|
||||||
@ -115,10 +201,38 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that the given permission is to be created for each new row in the target table.
|
||||||
|
*
|
||||||
|
* <p>Grants to permissions created by this method have to be specified separately,
|
||||||
|
* often it's easier to read to use createRole/createSubRole and use with.permission(...).</p>
|
||||||
|
*
|
||||||
|
* @param permission
|
||||||
|
* e.g. INSERT, SELECT, UPDATE, DELETE
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the newly created permission definition
|
||||||
|
*/
|
||||||
public RbacPermissionDefinition createPermission(final Permission permission) {
|
public RbacPermissionDefinition createPermission(final Permission permission) {
|
||||||
return createPermission(rootEntityAlias, permission);
|
return createPermission(rootEntityAlias, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that the given permission is to be created for each new row in the target table,
|
||||||
|
* but for another table, e.g. a table with details data with different access rights.
|
||||||
|
*
|
||||||
|
* <p>Grants to permissions created by this method have to be specified separately,
|
||||||
|
* often it's easier to read to use createRole/createSubRole and use with.permission(...).</p>
|
||||||
|
*
|
||||||
|
* @param entityAliasName
|
||||||
|
* A previously defined entity alias name.
|
||||||
|
*
|
||||||
|
* @param permission
|
||||||
|
* e.g. INSERT, SELECT, UPDATE, DELETE
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the newly created permission definition
|
||||||
|
*/
|
||||||
public RbacPermissionDefinition createPermission(final String entityAliasName, final Permission permission) {
|
public RbacPermissionDefinition createPermission(final String entityAliasName, final Permission permission) {
|
||||||
return createPermission(findEntityAlias(entityAliasName), permission);
|
return createPermission(findEntityAlias(entityAliasName), permission);
|
||||||
}
|
}
|
||||||
@ -134,6 +248,32 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports the RBAC template from the given entity class and defines an alias name for it.
|
||||||
|
* This method is especially for proxy-entities, if the root entity does not have its own
|
||||||
|
* roles, a proxy-entity can be specified and its roles can be used instead.
|
||||||
|
*
|
||||||
|
* @param aliasName
|
||||||
|
* An alias name for the entity class. The same entity class can be imported multiple times,
|
||||||
|
* if multiple references to its table exist, then distinct alias names habe to be defined.
|
||||||
|
*
|
||||||
|
* @param entityClass
|
||||||
|
* A JPA entity class extending RbacObject which also implements an `rbac` method returning
|
||||||
|
* its RBAC specification.
|
||||||
|
*
|
||||||
|
* @param fetchSql
|
||||||
|
* An SQL SELECT statement which fetches the referenced row. Use `${REF}` to speficiy the
|
||||||
|
* newly created or updated row (will be replaced by NEW/OLD from the trigger method).
|
||||||
|
*
|
||||||
|
* @param dependsOnColum
|
||||||
|
* The column, usually containing an uuid, on which this other table depends.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the newly created permission definition
|
||||||
|
*
|
||||||
|
* @param <EC>
|
||||||
|
* a JPA entity class extending RbacObject
|
||||||
|
*/
|
||||||
public <EC extends RbacObject> RbacView importRootEntityAliasProxy(
|
public <EC extends RbacObject> RbacView importRootEntityAliasProxy(
|
||||||
final String aliasName,
|
final String aliasName,
|
||||||
final Class<? extends HasUuid> entityClass,
|
final Class<? extends HasUuid> entityClass,
|
||||||
@ -146,6 +286,18 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports the RBAC template from the given entity class and defines an alias name for it.
|
||||||
|
* This method is especially to declare sub-entities, e.g. details to a main object.
|
||||||
|
*
|
||||||
|
* @see {@link}
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the newly created permission definition
|
||||||
|
*
|
||||||
|
* @param <EC>
|
||||||
|
* a JPA entity class extending RbacObject
|
||||||
|
*/
|
||||||
public RbacView importSubEntityAlias(
|
public RbacView importSubEntityAlias(
|
||||||
final String aliasName, final Class<? extends HasUuid> entityClass,
|
final String aliasName, final Class<? extends HasUuid> entityClass,
|
||||||
final SQL fetchSql, final Column dependsOnColum) {
|
final SQL fetchSql, final Column dependsOnColum) {
|
||||||
@ -153,6 +305,33 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports the RBAC template from the given entity class and defines an anlias name for it.
|
||||||
|
*
|
||||||
|
* @param aliasName
|
||||||
|
* An alias name for the entity class. The same entity class can be imported multiple times,
|
||||||
|
* if multiple references to its table exist, then distinct alias names habe to be defined.
|
||||||
|
*
|
||||||
|
* @param entityClass
|
||||||
|
* A JPA entity class extending RbacObject which also implements an `rbac` method returning
|
||||||
|
* its RBAC specification.
|
||||||
|
*
|
||||||
|
* @param fetchSql
|
||||||
|
* An SQL SELECT statement which fetches the referenced row. Use `${REF}` to speficiy the
|
||||||
|
* newly created or updated row (will be replaced by NEW/OLD from the trigger method).
|
||||||
|
*
|
||||||
|
* @param dependsOnColum
|
||||||
|
* The column, usually containing an uuid, on which this other table depends.
|
||||||
|
*
|
||||||
|
* @param nullable
|
||||||
|
* Specifies whether the dependsOnColum is nullable or not.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* the newly created permission definition
|
||||||
|
*
|
||||||
|
* @param <EC>
|
||||||
|
* a JPA entity class extending RbacObject
|
||||||
|
*/
|
||||||
public RbacView importEntityAlias(
|
public RbacView importEntityAlias(
|
||||||
final String aliasName, final Class<? extends HasUuid> entityClass,
|
final String aliasName, final Class<? extends HasUuid> entityClass,
|
||||||
final Column dependsOnColum, final SQL fetchSql, final Nullable nullable) {
|
final Column dependsOnColum, final SQL fetchSql, final Nullable nullable) {
|
||||||
@ -160,13 +339,7 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RbacView importEntityAlias(
|
// TODO: remove once it's not used in HsOffice...Entity anymore
|
||||||
final String aliasName, final Class<? extends HasUuid> entityClass,
|
|
||||||
final Column dependsOnColum, final SQL fetchSql) {
|
|
||||||
importEntityAliasImpl(aliasName, entityClass, fetchSql, dependsOnColum, false, NOT_NULL);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RbacView importEntityAlias(
|
public RbacView importEntityAlias(
|
||||||
final String aliasName, final Class<? extends HasUuid> entityClass,
|
final String aliasName, final Class<? extends HasUuid> entityClass,
|
||||||
final Column dependsOnColum) {
|
final Column dependsOnColum) {
|
||||||
@ -232,6 +405,16 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts declaring a grant to a given role.
|
||||||
|
*
|
||||||
|
* @param entityAlias
|
||||||
|
* A previously speciried entity alias name.
|
||||||
|
* @param role
|
||||||
|
* OWNER, ADMIN, AGENT, ...
|
||||||
|
* @return
|
||||||
|
* a grant builder
|
||||||
|
*/
|
||||||
public RbacGrantBuilder toRole(final String entityAlias, final Role role) {
|
public RbacGrantBuilder toRole(final String entityAlias, final Role role) {
|
||||||
return new RbacGrantBuilder(entityAlias, role);
|
return new RbacGrantBuilder(entityAlias, role);
|
||||||
}
|
}
|
||||||
@ -430,6 +613,16 @@ public class RbacView {
|
|||||||
permDefs.add(this);
|
permDefs.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grants the permission under definition to the given role.
|
||||||
|
*
|
||||||
|
* @param entityAlias
|
||||||
|
* A previously declared entity alias name.
|
||||||
|
* @param role
|
||||||
|
* OWNER, ADMIN, ...
|
||||||
|
* @return
|
||||||
|
* The RbacView specification to which this permission definition belongs.
|
||||||
|
*/
|
||||||
public RbacView grantedTo(final String entityAlias, final Role role) {
|
public RbacView grantedTo(final String entityAlias, final Role role) {
|
||||||
findOrCreateGrantDef(this, findRbacRole(entityAlias, role)).toCreate();
|
findOrCreateGrantDef(this, findRbacRole(entityAlias, role)).toCreate();
|
||||||
return RbacView.this;
|
return RbacView.this;
|
||||||
@ -460,19 +653,61 @@ public class RbacView {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies which user becomes the owner of newly created objects.
|
||||||
|
* @param userRole
|
||||||
|
* GLOBAL_ADMIN, CREATOR, ...
|
||||||
|
* @return
|
||||||
|
* The grant definition for further chained calls.
|
||||||
|
*/
|
||||||
public RbacGrantDefinition owningUser(final RbacUserReference.UserRole userRole) {
|
public RbacGrantDefinition owningUser(final RbacUserReference.UserRole userRole) {
|
||||||
return grantRoleToUser(this, findUserRef(userRole));
|
return grantRoleToUser(this, findUserRef(userRole));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies which permission is to be created for newly created objects.
|
||||||
|
* @param permission
|
||||||
|
* INSERT, SELECT, ...
|
||||||
|
* @return
|
||||||
|
* The grant definition for further chained calls.
|
||||||
|
*/
|
||||||
public RbacGrantDefinition permission(final Permission permission) {
|
public RbacGrantDefinition permission(final Permission permission) {
|
||||||
return grantPermissionToRole(createPermission(entityAlias, permission), this);
|
return grantPermissionToRole(createPermission(entityAlias, permission), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies in incoming super role which gets granted the role under definition.
|
||||||
|
*
|
||||||
|
* <p>Incoming means an incoming grant arrow in our grant-diagrams.
|
||||||
|
* Super-role means that it's the role to which another role is granted.
|
||||||
|
* Both means actually the same, just in different aspects.</p>
|
||||||
|
*
|
||||||
|
* @param entityAlias
|
||||||
|
* A previously declared entity alias name.
|
||||||
|
* @param role
|
||||||
|
* OWNER, ADMIN, ...
|
||||||
|
* @return
|
||||||
|
* The grant definition for further chained calls.
|
||||||
|
*/
|
||||||
public RbacGrantDefinition incomingSuperRole(final String entityAlias, final Role role) {
|
public RbacGrantDefinition incomingSuperRole(final String entityAlias, final Role role) {
|
||||||
final var incomingSuperRole = findRbacRole(entityAlias, role);
|
final var incomingSuperRole = findRbacRole(entityAlias, role);
|
||||||
return grantSubRoleToSuperRole(this, incomingSuperRole);
|
return grantSubRoleToSuperRole(this, incomingSuperRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies in outgoing sub role which gets granted the role under definition.
|
||||||
|
*
|
||||||
|
* <p>Outgoing means an outgoing grant arrow in our grant-diagrams.
|
||||||
|
* Sub-role means which is granted to another role.
|
||||||
|
* Both means actually the same, just in different aspects.</p>
|
||||||
|
*
|
||||||
|
* @param entityAlias
|
||||||
|
* A previously declared entity alias name.
|
||||||
|
* @param role
|
||||||
|
* OWNER, ADMIN, ...
|
||||||
|
* @return
|
||||||
|
* The grant definition for further chained calls.
|
||||||
|
*/
|
||||||
public RbacGrantDefinition outgoingSubRole(final String entityAlias, final Role role) {
|
public RbacGrantDefinition outgoingSubRole(final String entityAlias, final Role role) {
|
||||||
final var outgoingSubRole = findRbacRole(entityAlias, role);
|
final var outgoingSubRole = findRbacRole(entityAlias, role);
|
||||||
return grantSubRoleToSuperRole(outgoingSubRole, this);
|
return grantSubRoleToSuperRole(outgoingSubRole, this);
|
||||||
@ -802,6 +1037,26 @@ public class RbacView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void generateRbacView(final Class<? extends HasUuid> c) {
|
||||||
|
final Method mainMethod = stream(c.getMethods()).filter(
|
||||||
|
m -> isStatic(m.getModifiers()) && m.getName().equals("main")
|
||||||
|
)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (mainMethod != null) {
|
||||||
|
try {
|
||||||
|
mainMethod.invoke(null, new Object[] { null });
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("WARNING: no main method in: " + c.getName() + " => no RBAC rules generated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This main method generates the RbacViews (PostgreSQL+diagram) for all given entity classes.
|
||||||
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Stream.of(
|
Stream.of(
|
||||||
TestCustomerEntity.class,
|
TestCustomerEntity.class,
|
||||||
@ -818,21 +1073,6 @@ public class RbacView {
|
|||||||
HsOfficeSepaMandateEntity.class,
|
HsOfficeSepaMandateEntity.class,
|
||||||
HsOfficeCoopSharesTransactionEntity.class,
|
HsOfficeCoopSharesTransactionEntity.class,
|
||||||
HsOfficeMembershipEntity.class
|
HsOfficeMembershipEntity.class
|
||||||
).forEach(c -> {
|
).forEach(RbacView::generateRbacView);
|
||||||
final Method mainMethod = stream(c.getMethods()).filter(
|
|
||||||
m -> isStatic(m.getModifiers()) && m.getName().equals("main")
|
|
||||||
)
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
if (mainMethod != null) {
|
|
||||||
try {
|
|
||||||
mainMethod.invoke(null, new Object[] { null });
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.err.println("WARNING: no main method in: " + c.getName() + " => no RBAC rules generated");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import lombok.SneakyThrows;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
import static java.util.stream.Collectors.joining;
|
import static java.util.stream.Collectors.joining;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacGrantDefinition.GrantType.*;
|
||||||
@ -149,14 +148,13 @@ public class RbacViewMermaidFlowchartGenerator {
|
|||||||
"""
|
"""
|
||||||
### rbac %{entityAlias}
|
### rbac %{entityAlias}
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at %{timestamp}.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%{flowchart}
|
%{flowchart}
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
.replace("%{entityAlias}", rbacDef.getRootEntityAlias().aliasName())
|
.replace("%{entityAlias}", rbacDef.getRootEntityAlias().aliasName())
|
||||||
.replace("%{timestamp}", LocalDateTime.now().toString())
|
|
||||||
.replace("%{flowchart}", flowchart.toString()),
|
.replace("%{flowchart}", flowchart.toString()),
|
||||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
System.out.println("Markdown-File: " + path.toAbsolutePath());
|
System.out.println("Markdown-File: " + path.toAbsolutePath());
|
||||||
|
@ -5,7 +5,6 @@ import lombok.SneakyThrows;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.PostgresTriggerReference.NEW;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.PostgresTriggerReference.NEW;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.StringWriter.with;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.StringWriter.with;
|
||||||
@ -21,10 +20,9 @@ public class RbacViewPostgresGenerator {
|
|||||||
liqibaseTagPrefix = rbacDef.getRootEntityAlias().getRawTableName().replace("_", "-");
|
liqibaseTagPrefix = rbacDef.getRootEntityAlias().getRawTableName().replace("_", "-");
|
||||||
plPgSql.writeLn("""
|
plPgSql.writeLn("""
|
||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by ${generator} at ${timestamp}.
|
-- This code generated was by ${generator}, do not amend manually.
|
||||||
""",
|
""",
|
||||||
with("generator", getClass().getSimpleName()),
|
with("generator", getClass().getSimpleName()),
|
||||||
with("timestamp", LocalDateTime.now().toString()),
|
|
||||||
with("ref", NEW.name()));
|
with("ref", NEW.name()));
|
||||||
|
|
||||||
new RbacObjectGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql);
|
new RbacObjectGenerator(rbacDef, liqibaseTagPrefix).generateTo(plPgSql);
|
||||||
|
@ -28,8 +28,8 @@ public class RawRbacGrantEntity implements Comparable {
|
|||||||
@Column(name = "grantedbyroleidname", updatable = false, insertable = false)
|
@Column(name = "grantedbyroleidname", updatable = false, insertable = false)
|
||||||
private String grantedByRoleIdName;
|
private String grantedByRoleIdName;
|
||||||
|
|
||||||
@Column(name = "usergrantsbyroleuuid", updatable = false, insertable = false)
|
@Column(name = "grantedbyroleuuid", updatable = false, insertable = false)
|
||||||
private UUID userGrantsByRoleUuid;
|
private UUID grantedByRoleUuid;
|
||||||
|
|
||||||
@Column(name = "ascendantidname", updatable = false, insertable = false)
|
@Column(name = "ascendantidname", updatable = false, insertable = false)
|
||||||
private String ascendantIdName;
|
private String ascendantIdName;
|
||||||
@ -50,7 +50,7 @@ public class RawRbacGrantEntity implements Comparable {
|
|||||||
// @formatter:off
|
// @formatter:off
|
||||||
return "{ grant " + descendantIdName +
|
return "{ grant " + descendantIdName +
|
||||||
" to " + ascendantIdName +
|
" to " + ascendantIdName +
|
||||||
" by " + ( userGrantsByRoleUuid == null
|
" by " + ( grantedByRoleUuid == null
|
||||||
? "system"
|
? "system"
|
||||||
: grantedByRoleIdName ) +
|
: grantedByRoleIdName ) +
|
||||||
( assumed ? " and assume" : "") +
|
( assumed ? " and assume" : "") +
|
||||||
|
@ -22,8 +22,8 @@ public class RbacGrantEntity {
|
|||||||
@Column(name = "grantedbyroleidname", updatable = false, insertable = false)
|
@Column(name = "grantedbyroleidname", updatable = false, insertable = false)
|
||||||
private String grantedByRoleIdName;
|
private String grantedByRoleIdName;
|
||||||
|
|
||||||
@Column(name = "usergrantsbyroleuuid", updatable = false, insertable = false)
|
@Column(name = "grantedbyroleuuid", updatable = false, insertable = false)
|
||||||
private UUID userGrantsByRoleUuid;
|
private UUID grantedByRoleUuid;
|
||||||
|
|
||||||
@Column(name = "grantedroleidname", updatable = false, insertable = false)
|
@Column(name = "grantedroleidname", updatable = false, insertable = false)
|
||||||
private String grantedRoleIdName;
|
private String grantedRoleIdName;
|
||||||
|
@ -14,6 +14,7 @@ import java.io.IOException;
|
|||||||
import java.util.UUID;
|
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.Nullable.NOT_NULL;
|
||||||
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.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;
|
||||||
@ -52,7 +53,8 @@ public class TestDomainEntity implements HasUuid {
|
|||||||
fetchedBySql("""
|
fetchedBySql("""
|
||||||
SELECT * FROM test_package p
|
SELECT * FROM test_package p
|
||||||
WHERE p.uuid= ${ref}.packageUuid
|
WHERE p.uuid= ${ref}.packageUuid
|
||||||
"""))
|
"""),
|
||||||
|
NOT_NULL)
|
||||||
.toRole("package", ADMIN).grantPermission(INSERT)
|
.toRole("package", ADMIN).grantPermission(INSERT)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
|
@ -14,6 +14,7 @@ import java.io.IOException;
|
|||||||
import java.util.UUID;
|
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.Nullable.NOT_NULL;
|
||||||
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.Role.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.*;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.*;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL.*;
|
||||||
@ -53,7 +54,8 @@ public class TestPackageEntity implements HasUuid {
|
|||||||
fetchedBySql("""
|
fetchedBySql("""
|
||||||
SELECT * FROM test_customer c
|
SELECT * FROM test_customer c
|
||||||
WHERE c.uuid= ${ref}.customerUuid
|
WHERE c.uuid= ${ref}.customerUuid
|
||||||
"""))
|
"""),
|
||||||
|
NOT_NULL)
|
||||||
.toRole("customer", ADMIN).grantPermission(INSERT)
|
.toRole("customer", ADMIN).grantPermission(INSERT)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
|
@ -160,6 +160,7 @@ create or replace function cleanIdentifier(rawIdentifier varchar)
|
|||||||
declare
|
declare
|
||||||
cleanIdentifier varchar;
|
cleanIdentifier varchar;
|
||||||
begin
|
begin
|
||||||
|
-- TODO: remove the ':' from the list of allowed characters as soon as it's not used anymore
|
||||||
cleanIdentifier := regexp_replace(rawIdentifier, '[^A-Za-z0-9\-._:]+', '', 'g');
|
cleanIdentifier := regexp_replace(rawIdentifier, '[^A-Za-z0-9\-._:]+', '', 'g');
|
||||||
return cleanIdentifier;
|
return cleanIdentifier;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
@ -300,7 +300,7 @@ create or replace function deleteRbacGrantsOfRbacRole()
|
|||||||
strict as $$
|
strict as $$
|
||||||
begin
|
begin
|
||||||
if TG_OP = 'DELETE' then
|
if TG_OP = 'DELETE' then
|
||||||
delete from RbacGrants g where old.uuid in (g.userGrantsByRoleUuid, g.ascendantuuid, g.descendantuuid);
|
delete from RbacGrants g where old.uuid in (g.grantedbyroleuuid, g.ascendantuuid, g.descendantuuid);
|
||||||
else
|
else
|
||||||
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
|
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
|
||||||
end if;
|
end if;
|
||||||
@ -519,12 +519,12 @@ 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 ,
|
grantedByTriggerOf uuid references RbacObject (uuid) on delete cascade initially deferred ,
|
||||||
userGrantsByRoleUuid 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 ( userGrantsByRoleUuid is null or grantedByTriggerOf is null) );
|
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);
|
||||||
|
|
||||||
|
@ -20,52 +20,50 @@ begin
|
|||||||
return currentSubjectsUuids[1];
|
return currentSubjectsUuids[1];
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create or replace procedure grantRoleToUserUnchecked(userGrantsByRoleUuid uuid, roleUuid uuid, userUuid uuid, doAssume boolean = true)
|
create or replace procedure grantRoleToUserUnchecked(grantedByRoleUuid uuid, roleUuid uuid, userUuid uuid, doAssume boolean = true)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
perform assertReferenceType('grantingRoleUuid', userGrantsByRoleUuid, 'RbacRole');
|
perform assertReferenceType('grantingRoleUuid', grantedByRoleUuid, 'RbacRole');
|
||||||
perform assertReferenceType('roleId (descendant)', roleUuid, 'RbacRole');
|
perform assertReferenceType('roleId (descendant)', roleUuid, 'RbacRole');
|
||||||
perform assertReferenceType('userId (ascendant)', userUuid, 'RbacUser');
|
perform assertReferenceType('userId (ascendant)', userUuid, 'RbacUser');
|
||||||
|
|
||||||
raise notice 'role % grants role % to user %, assumed=%', userGrantsByRoleUuid, roleUuid, userUuid, doAssume;
|
|
||||||
|
|
||||||
insert
|
insert
|
||||||
into RbacGrants (userGrantsByRoleUuid, ascendantUuid, descendantUuid, assumed)
|
into RbacGrants (grantedByRoleUuid, ascendantUuid, descendantUuid, assumed)
|
||||||
values (userGrantsByRoleUuid, userUuid, roleUuid, doAssume);
|
values (grantedByRoleUuid, userUuid, roleUuid, doAssume);
|
||||||
-- TODO.spec: What should happen on multiple grants? What if options (doAssume) are not the same?
|
-- TODO.spec: What should happen on multiple grants? What if options (doAssume) are not the same?
|
||||||
-- Most powerful or latest grant wins? What about managed?
|
-- Most powerful or latest grant wins? What about managed?
|
||||||
-- on conflict do nothing; -- allow granting multiple times
|
-- on conflict do nothing; -- allow granting multiple times
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create or replace procedure grantRoleToUser(userGrantsByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid, doAssume boolean = true)
|
create or replace procedure grantRoleToUser(grantedByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid, doAssume boolean = true)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
declare
|
declare
|
||||||
grantedByRoleIdName text;
|
grantedByRoleIdName text;
|
||||||
grantedRoleIdName text;
|
grantedRoleIdName text;
|
||||||
begin
|
begin
|
||||||
perform assertReferenceType('grantingRoleUuid', userGrantsByRoleUuid, 'RbacRole');
|
perform assertReferenceType('grantingRoleUuid', grantedByRoleUuid, 'RbacRole');
|
||||||
perform assertReferenceType('grantedRoleUuid (descendant)', grantedRoleUuid, 'RbacRole');
|
perform assertReferenceType('grantedRoleUuid (descendant)', grantedRoleUuid, 'RbacRole');
|
||||||
perform assertReferenceType('userUuid (ascendant)', userUuid, 'RbacUser');
|
perform assertReferenceType('userUuid (ascendant)', userUuid, 'RbacUser');
|
||||||
|
|
||||||
assert userGrantsByRoleUuid is not null, 'userGrantsByRoleUuid must not be null';
|
assert grantedByRoleUuid is not null, 'grantedByRoleUuid must not be null';
|
||||||
assert grantedRoleUuid is not null, 'grantedRoleUuid must not be null';
|
assert grantedRoleUuid is not null, 'grantedRoleUuid must not be null';
|
||||||
assert userUuid is not null, 'userUuid must not be null';
|
assert userUuid is not null, 'userUuid must not be null';
|
||||||
|
|
||||||
if NOT isGranted(currentSubjectsUuids(), userGrantsByRoleUuid) then
|
if NOT isGranted(currentSubjectsUuids(), grantedByRoleUuid) then
|
||||||
select roleIdName from rbacRole_ev where uuid=userGrantsByRoleUuid into grantedByRoleIdName;
|
select roleIdName from rbacRole_ev where uuid=grantedByRoleUuid into grantedByRoleIdName;
|
||||||
raise exception '[403] Access to granted-by-role % (%) forbidden for % (%)',
|
raise exception '[403] Access to granted-by-role % (%) forbidden for % (%)',
|
||||||
grantedByRoleIdName, userGrantsByRoleUuid, currentSubjects(), currentSubjectsUuids();
|
grantedByRoleIdName, grantedByRoleUuid, currentSubjects(), currentSubjectsUuids();
|
||||||
end if;
|
end if;
|
||||||
if NOT isGranted(userGrantsByRoleUuid, grantedRoleUuid) then
|
if NOT isGranted(grantedByRoleUuid, grantedRoleUuid) then
|
||||||
select roleIdName from rbacRole_ev where uuid=userGrantsByRoleUuid into grantedByRoleIdName;
|
select roleIdName from rbacRole_ev where uuid=grantedByRoleUuid into grantedByRoleIdName;
|
||||||
select roleIdName from rbacRole_ev where uuid=grantedRoleUuid into grantedRoleIdName;
|
select roleIdName from rbacRole_ev where uuid=grantedRoleUuid into grantedRoleIdName;
|
||||||
raise exception '[403] Access to granted role % (%) forbidden for % (%)',
|
raise exception '[403] Access to granted role % (%) forbidden for % (%)',
|
||||||
grantedRoleIdName, grantedRoleUuid, grantedByRoleIdName, userGrantsByRoleUuid;
|
grantedRoleIdName, grantedRoleUuid, grantedByRoleIdName, grantedByRoleUuid;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
insert
|
insert
|
||||||
into RbacGrants (userGrantsByRoleUuid, ascendantUuid, descendantUuid, assumed)
|
into RbacGrants (grantedByRoleUuid, ascendantUuid, descendantUuid, assumed)
|
||||||
values (userGrantsByRoleUuid, userUuid, grantedRoleUuid, doAssume);
|
values (grantedByRoleUuid, userUuid, grantedRoleUuid, doAssume);
|
||||||
-- TODO.spec: What should happen on mupltiple grants? What if options (doAssume) are not the same?
|
-- TODO.spec: What should happen on mupltiple grants? What if options (doAssume) are not the same?
|
||||||
-- Most powerful or latest grant wins? What about managed?
|
-- Most powerful or latest grant wins? What about managed?
|
||||||
-- on conflict do nothing; -- allow granting multiple times
|
-- on conflict do nothing; -- allow granting multiple times
|
||||||
@ -77,40 +75,40 @@ end; $$;
|
|||||||
--changeset rbac-user-grant-REVOKE-ROLE-FROM-USER:1 endDelimiter:--//
|
--changeset rbac-user-grant-REVOKE-ROLE-FROM-USER:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
create or replace procedure checkRevokeRoleFromUserPreconditions(userGrantsByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid)
|
create or replace procedure checkRevokeRoleFromUserPreconditions(grantedByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
perform assertReferenceType('userGrantsByRoleUuid', userGrantsByRoleUuid, 'RbacRole');
|
perform assertReferenceType('grantedByRoleUuid', grantedByRoleUuid, 'RbacRole');
|
||||||
perform assertReferenceType('grantedRoleUuid (descendant)', grantedRoleUuid, 'RbacRole');
|
perform assertReferenceType('grantedRoleUuid (descendant)', grantedRoleUuid, 'RbacRole');
|
||||||
perform assertReferenceType('userUuid (ascendant)', userUuid, 'RbacUser');
|
perform assertReferenceType('userUuid (ascendant)', userUuid, 'RbacUser');
|
||||||
|
|
||||||
if NOT isGranted(currentSubjectsUuids(), userGrantsByRoleUuid) then
|
if NOT isGranted(currentSubjectsUuids(), grantedByRoleUuid) then
|
||||||
raise exception '[403] Revoking role created by % is forbidden for %.', userGrantsByRoleUuid, currentSubjects();
|
raise exception '[403] Revoking role created by % is forbidden for %.', grantedByRoleUuid, currentSubjects();
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
if NOT isGranted(userGrantsByRoleUuid, grantedRoleUuid) then
|
if NOT isGranted(grantedByRoleUuid, grantedRoleUuid) then
|
||||||
raise exception '[403] Revoking role % is forbidden for %.', grantedRoleUuid, currentSubjects();
|
raise exception '[403] Revoking role % is forbidden for %.', grantedRoleUuid, currentSubjects();
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
--raise exception 'isGranted(%, %)', currentSubjectsUuids(), userGrantsByRoleUuid;
|
--raise exception 'isGranted(%, %)', currentSubjectsUuids(), grantedByRoleUuid;
|
||||||
if NOT isGranted(currentSubjectsUuids(), userGrantsByRoleUuid) then
|
if NOT isGranted(currentSubjectsUuids(), grantedByRoleUuid) then
|
||||||
raise exception '[403] Revoking role granted by % is forbidden for %.', userGrantsByRoleUuid, currentSubjects();
|
raise exception '[403] Revoking role granted by % is forbidden for %.', grantedByRoleUuid, currentSubjects();
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
if NOT isGranted(userUuid, grantedRoleUuid) then
|
if NOT isGranted(userUuid, grantedRoleUuid) then
|
||||||
raise exception '[404] No such grant found granted by % for user % to role %.', userGrantsByRoleUuid, userUuid, grantedRoleUuid;
|
raise exception '[404] No such grant found granted by % for user % to role %.', grantedByRoleUuid, userUuid, grantedRoleUuid;
|
||||||
end if;
|
end if;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create or replace procedure revokeRoleFromUser(userGrantsByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid)
|
create or replace procedure revokeRoleFromUser(grantedByRoleUuid uuid, grantedRoleUuid uuid, userUuid uuid)
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
call checkRevokeRoleFromUserPreconditions(userGrantsByRoleUuid, grantedRoleUuid, userUuid);
|
call checkRevokeRoleFromUserPreconditions(grantedByRoleUuid, grantedRoleUuid, userUuid);
|
||||||
|
|
||||||
raise INFO 'delete from RbacGrants where ascendantUuid = % and descendantUuid = %', userUuid, grantedRoleUuid;
|
raise INFO 'delete from RbacGrants where ascendantUuid = % and descendantUuid = %', userUuid, grantedRoleUuid;
|
||||||
delete from RbacGrants as g
|
delete from RbacGrants as g
|
||||||
where g.ascendantUuid = userUuid and g.descendantUuid = grantedRoleUuid
|
where g.ascendantUuid = userUuid and g.descendantUuid = grantedRoleUuid
|
||||||
and g.userGrantsByRoleUuid = revokeRoleFromUser.userGrantsByRoleUuid;
|
and g.grantedByRoleUuid = revokeRoleFromUser.grantedByRoleUuid;
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -139,7 +139,6 @@ begin
|
|||||||
raise exception '[401] currentUserUuid cannot be determined, please call `defineContext(...)` first;"';
|
raise exception '[401] currentUserUuid cannot be determined, please call `defineContext(...)` first;"';
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
raise notice 'currentUserUuid %', currentUserUuid;
|
|
||||||
return currentUserUuid::uuid;
|
return currentUserUuid::uuid;
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
@ -60,14 +60,14 @@ create or replace view rbacgrants_ev as
|
|||||||
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,
|
||||||
x.userGrantsByRoleUuid,
|
x.grantedByRoleUuid,
|
||||||
x.ascendantUuid as ascendantUuid,
|
x.ascendantUuid as ascendantUuid,
|
||||||
x.descendantUuid as descendantUuid,
|
x.descendantUuid as descendantUuid,
|
||||||
x.assumed
|
x.assumed
|
||||||
from (
|
from (
|
||||||
select g.uuid as grantUuid,
|
select g.uuid as grantUuid,
|
||||||
g.grantedbytriggerof as grantedbytriggerof,
|
g.grantedbytriggerof as grantedbytriggerof,
|
||||||
g.userGrantsByRoleUuid, g.ascendantuuid, g.descendantuuid, g.assumed,
|
g.grantedbyroleuuid, g.ascendantuuid, g.descendantuuid, g.assumed,
|
||||||
|
|
||||||
coalesce(
|
coalesce(
|
||||||
'user ' || au.name,
|
'user ' || au.name,
|
||||||
@ -91,7 +91,7 @@ create or replace view rbacgrants_ev as
|
|||||||
left outer join rbacpermission dp on dp.uuid = g.descendantUuid
|
left outer join rbacpermission dp on dp.uuid = g.descendantUuid
|
||||||
left outer join rbacobject as dpo on dpo.uuid = dp.objectUuid
|
left outer join rbacobject as dpo on dpo.uuid = dp.objectUuid
|
||||||
) as x
|
) as x
|
||||||
left outer join rbacrole as r on r.uuid = userGrantsByRoleUuid
|
left outer join rbacrole as r on r.uuid = grantedByRoleUuid
|
||||||
left outer join rbacuser u on u.uuid = x.ascendantuuid
|
left outer join rbacuser u on u.uuid = x.ascendantuuid
|
||||||
left outer join rbacobject go on go.uuid = r.objectuuid
|
left outer join rbacobject go on go.uuid = r.objectuuid
|
||||||
|
|
||||||
@ -112,10 +112,10 @@ create or replace view rbacgrants_rv as
|
|||||||
-- @formatter:off
|
-- @formatter:off
|
||||||
select o.objectTable || '#' || findIdNameByObjectUuid(o.objectTable, o.uuid) || '.' || r.roletype as grantedByRoleIdName,
|
select o.objectTable || '#' || findIdNameByObjectUuid(o.objectTable, o.uuid) || '.' || r.roletype as grantedByRoleIdName,
|
||||||
g.objectTable || '#' || g.objectIdName || '.' || g.roletype as grantedRoleIdName, g.userName, g.assumed,
|
g.objectTable || '#' || g.objectIdName || '.' || g.roletype as grantedRoleIdName, g.userName, g.assumed,
|
||||||
g.userGrantsByRoleUuid, g.descendantUuid as grantedRoleUuid, g.ascendantUuid as userUuid,
|
g.grantedByRoleUuid, g.descendantUuid as grantedRoleUuid, g.ascendantUuid as userUuid,
|
||||||
g.objectTable, g.objectUuid, g.objectIdName, g.roleType as grantedRoleType
|
g.objectTable, g.objectUuid, g.objectIdName, g.roleType as grantedRoleType
|
||||||
from (
|
from (
|
||||||
select g.userGrantsByRoleUuid, g.ascendantuuid, g.descendantuuid, g.assumed,
|
select g.grantedbyroleuuid, g.ascendantuuid, g.descendantuuid, g.assumed,
|
||||||
u.name as userName, o.objecttable, r.objectuuid, r.roletype,
|
u.name as userName, o.objecttable, r.objectuuid, r.roletype,
|
||||||
findIdNameByObjectUuid(o.objectTable, o.uuid) as objectIdName
|
findIdNameByObjectUuid(o.objectTable, o.uuid) as objectIdName
|
||||||
from rbacgrants as g
|
from rbacgrants as g
|
||||||
@ -124,7 +124,7 @@ select o.objectTable || '#' || findIdNameByObjectUuid(o.objectTable, o.uuid) ||
|
|||||||
left outer join rbacuser u on u.uuid = g.ascendantuuid
|
left outer join rbacuser u on u.uuid = g.ascendantuuid
|
||||||
where isGranted(currentSubjectsUuids(), r.uuid)
|
where isGranted(currentSubjectsUuids(), r.uuid)
|
||||||
) as g
|
) as g
|
||||||
join RbacRole as r on r.uuid = userGrantsByRoleUuid
|
join RbacRole as r on r.uuid = grantedByRoleUuid
|
||||||
join RbacObject as o on o.uuid = r.objectUuid
|
join RbacObject as o on o.uuid = r.objectUuid
|
||||||
order by grantedRoleIdName;
|
order by grantedRoleIdName;
|
||||||
-- @formatter:on
|
-- @formatter:on
|
||||||
@ -177,7 +177,7 @@ create or replace function deleteRbacGrant()
|
|||||||
returns trigger
|
returns trigger
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
call revokeRoleFromUser(old.userGrantsByRoleUuid, old.grantedRoleUuid, old.userUuid);
|
call revokeRoleFromUser(old.grantedByRoleUuid, old.grantedRoleUuid, old.userUuid);
|
||||||
return old;
|
return old;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac customer
|
### rbac customer
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-22T14:44:19.425403022.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
@ -21,6 +21,7 @@ subgraph customer["`**customer**`"]
|
|||||||
subgraph customer:permissions[ ]
|
subgraph customer:permissions[ ]
|
||||||
style customer:permissions fill:#dd4901,stroke:white
|
style customer:permissions fill:#dd4901,stroke:white
|
||||||
|
|
||||||
|
perm:customer:INSERT{{customer:INSERT}}
|
||||||
perm:customer:DELETE{{customer:DELETE}}
|
perm:customer:DELETE{{customer:DELETE}}
|
||||||
perm:customer:UPDATE{{customer:UPDATE}}
|
perm:customer:UPDATE{{customer:UPDATE}}
|
||||||
perm:customer:SELECT{{customer:SELECT}}
|
perm:customer:SELECT{{customer:SELECT}}
|
||||||
@ -36,6 +37,7 @@ role:customer:owner ==> role:customer:admin
|
|||||||
role:customer:admin ==> role:customer:tenant
|
role:customer:admin ==> role:customer:tenant
|
||||||
|
|
||||||
%% granting permissions to roles
|
%% granting permissions to roles
|
||||||
|
role:global:admin ==> perm:customer:INSERT
|
||||||
role:customer:owner ==> perm:customer:DELETE
|
role:customer:owner ==> perm:customer:DELETE
|
||||||
role:customer:admin ==> perm:customer:UPDATE
|
role:customer:admin ==> perm:customer:UPDATE
|
||||||
role:customer:tenant ==> perm:customer:SELECT
|
role:customer:tenant ==> perm:customer:SELECT
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-22T14:44:19.441879428.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -80,6 +80,46 @@ execute procedure insertTriggerForTestCustomer_tf();
|
|||||||
--changeset test-customer-rbac-INSERT:1 endDelimiter:--//
|
--changeset test-customer-rbac-INSERT:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates INSERT INTO test_customer permissions for the related global rows.
|
||||||
|
*/
|
||||||
|
do language plpgsql $$
|
||||||
|
declare
|
||||||
|
row global;
|
||||||
|
permissionUuid uuid;
|
||||||
|
roleUuid uuid;
|
||||||
|
begin
|
||||||
|
call defineContext('create INSERT INTO test_customer permissions for the related global rows');
|
||||||
|
|
||||||
|
FOR row IN SELECT * FROM global
|
||||||
|
LOOP
|
||||||
|
roleUuid := findRoleId(globalAdmin());
|
||||||
|
permissionUuid := createPermission(row.uuid, 'INSERT', 'test_customer');
|
||||||
|
call grantPermissionToRole(permissionUuid, roleUuid);
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds test_customer INSERT permission to specified role of new global rows.
|
||||||
|
*/
|
||||||
|
create or replace function test_customer_global_insert_tf()
|
||||||
|
returns trigger
|
||||||
|
language plpgsql
|
||||||
|
strict as $$
|
||||||
|
begin
|
||||||
|
call grantPermissionToRole(
|
||||||
|
createPermission(NEW.uuid, 'INSERT', 'test_customer'),
|
||||||
|
globalAdmin());
|
||||||
|
return NEW;
|
||||||
|
end; $$;
|
||||||
|
|
||||||
|
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
|
||||||
|
create trigger z_test_customer_global_insert_tg
|
||||||
|
after insert on global
|
||||||
|
for each row
|
||||||
|
execute procedure test_customer_global_insert_tf();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to test_customer,
|
Checks if the user or assumed roles are allowed to insert a row to test_customer,
|
||||||
where only global-admin has that permission.
|
where only global-admin has that permission.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac package
|
### rbac package
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-22T14:44:19.484173294.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-22T12:01:44.554331877.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -195,32 +195,22 @@ execute procedure test_package_test_customer_insert_tf();
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to test_package,
|
Checks if the user or assumed roles are allowed to insert a row to test_package,
|
||||||
where the check is performed by an indirect role.
|
where the check is performed by a direct role.
|
||||||
|
|
||||||
An indirect role is a role FIXME.
|
A direct role is a role depending on a foreign key directly available in the NEW row.
|
||||||
*/
|
*/
|
||||||
create or replace function test_package_insert_permission_missing_tf()
|
create or replace function test_package_insert_permission_missing_tf()
|
||||||
returns trigger
|
returns trigger
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
if ( not hasInsertPermission(
|
raise exception '[403] insert into test_package not allowed for current subjects % (%)',
|
||||||
( SELECT customer.uuid FROM
|
|
||||||
|
|
||||||
(SELECT * FROM test_customer c
|
|
||||||
WHERE c.uuid= NEW.customerUuid
|
|
||||||
) AS customer
|
|
||||||
|
|
||||||
), 'INSERT', 'test_package') ) then
|
|
||||||
raise exception
|
|
||||||
'[403] insert into test_package not allowed for current subjects % (%)',
|
|
||||||
currentSubjects(), currentSubjectsUuids();
|
currentSubjects(), currentSubjectsUuids();
|
||||||
end if;
|
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create trigger test_package_insert_permission_check_tg
|
create trigger test_package_insert_permission_check_tg
|
||||||
before insert on test_package
|
before insert on test_package
|
||||||
for each row
|
for each row
|
||||||
|
when ( not hasInsertPermission(NEW.customerUuid, 'INSERT', 'test_package') )
|
||||||
execute procedure test_package_insert_permission_missing_tf();
|
execute procedure test_package_insert_permission_missing_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac domain
|
### rbac domain
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-22T14:44:19.510830235.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-11T11:29:11.645391647.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset test-domain-rbac-OBJECT:1 endDelimiter:--//
|
--changeset test-domain-rbac-OBJECT:1 endDelimiter:--//
|
||||||
@ -33,9 +34,12 @@ declare
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
call enterTriggerForObjectUuid(NEW.uuid);
|
call enterTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
SELECT * FROM test_package p
|
SELECT * FROM test_package p
|
||||||
WHERE p.uuid= NEW.packageUuid
|
WHERE p.uuid= NEW.packageUuid
|
||||||
into newPackage;
|
INTO newPackage;
|
||||||
|
assert newPackage.uuid is not null, format('newPackage must not be null for NEW.packageUuid = %s', NEW.packageUuid);
|
||||||
|
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
testDomainOwner(NEW),
|
testDomainOwner(NEW),
|
||||||
@ -71,9 +75,9 @@ create trigger insertTriggerForTestDomain_tg
|
|||||||
after insert on test_domain
|
after insert on test_domain
|
||||||
for each row
|
for each row
|
||||||
execute procedure insertTriggerForTestDomain_tf();
|
execute procedure insertTriggerForTestDomain_tf();
|
||||||
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset test-domain-rbac-update-trigger:1 endDelimiter:--//
|
--changeset test-domain-rbac-update-trigger:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
@ -97,14 +101,18 @@ begin
|
|||||||
|
|
||||||
SELECT * FROM test_package p
|
SELECT * FROM test_package p
|
||||||
WHERE p.uuid= OLD.packageUuid
|
WHERE p.uuid= OLD.packageUuid
|
||||||
into oldPackage;
|
INTO oldPackage;
|
||||||
|
assert oldPackage.uuid is not null, format('oldPackage must not be null for OLD.packageUuid = %s', OLD.packageUuid);
|
||||||
|
|
||||||
SELECT * FROM test_package p
|
SELECT * FROM test_package p
|
||||||
WHERE p.uuid= NEW.packageUuid
|
WHERE p.uuid= NEW.packageUuid
|
||||||
into newPackage;
|
INTO newPackage;
|
||||||
|
assert newPackage.uuid is not null, format('newPackage must not be null for NEW.packageUuid = %s', NEW.packageUuid);
|
||||||
|
|
||||||
|
|
||||||
if NEW.packageUuid <> OLD.packageUuid then
|
if NEW.packageUuid <> OLD.packageUuid then
|
||||||
|
|
||||||
call revokePermissionFromRole(findPermissionId(OLD.uuid, 'INSERT'), testPackageAdmin(oldPackage));
|
call revokePermissionFromRole(getPermissionId(OLD.uuid, 'INSERT'), testPackageAdmin(oldPackage));
|
||||||
|
|
||||||
call revokeRoleFromRole(testDomainOwner(OLD), testPackageAdmin(oldPackage));
|
call revokeRoleFromRole(testDomainOwner(OLD), testPackageAdmin(oldPackage));
|
||||||
call grantRoleToRole(testDomainOwner(NEW), testPackageAdmin(newPackage));
|
call grantRoleToRole(testDomainOwner(NEW), testPackageAdmin(newPackage));
|
||||||
@ -137,9 +145,9 @@ create trigger updateTriggerForTestDomain_tg
|
|||||||
after update on test_domain
|
after update on test_domain
|
||||||
for each row
|
for each row
|
||||||
execute procedure updateTriggerForTestDomain_tf();
|
execute procedure updateTriggerForTestDomain_tf();
|
||||||
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset test-domain-rbac-INSERT:1 endDelimiter:--//
|
--changeset test-domain-rbac-INSERT:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
@ -178,13 +186,17 @@ begin
|
|||||||
return NEW;
|
return NEW;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
|
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
|
||||||
create trigger z_test_domain_test_package_insert_tg
|
create trigger z_test_domain_test_package_insert_tg
|
||||||
after insert on test_package
|
after insert on test_package
|
||||||
for each row
|
for each row
|
||||||
execute procedure test_domain_test_package_insert_tf();
|
execute procedure test_domain_test_package_insert_tf();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to test_domain.
|
Checks if the user or assumed roles are allowed to insert a row to test_domain,
|
||||||
|
where the check is performed by a direct role.
|
||||||
|
|
||||||
|
A direct role is a role depending on a foreign key directly available in the NEW row.
|
||||||
*/
|
*/
|
||||||
create or replace function test_domain_insert_permission_missing_tf()
|
create or replace function test_domain_insert_permission_missing_tf()
|
||||||
returns trigger
|
returns trigger
|
||||||
@ -199,8 +211,8 @@ create trigger test_domain_insert_permission_check_tg
|
|||||||
for each row
|
for each row
|
||||||
when ( not hasInsertPermission(NEW.packageUuid, 'INSERT', 'test_domain') )
|
when ( not hasInsertPermission(NEW.packageUuid, 'INSERT', 'test_domain') )
|
||||||
execute procedure test_domain_insert_permission_missing_tf();
|
execute procedure test_domain_insert_permission_missing_tf();
|
||||||
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset test-domain-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
--changeset test-domain-rbac-IDENTITY-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
@ -208,13 +220,15 @@ create trigger test_domain_insert_permission_check_tg
|
|||||||
call generateRbacIdentityViewFromProjection('test_domain', $idName$
|
call generateRbacIdentityViewFromProjection('test_domain', $idName$
|
||||||
name
|
name
|
||||||
$idName$);
|
$idName$);
|
||||||
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--changeset test-domain-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
--changeset test-domain-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
|
||||||
-- ----------------------------------------------------------------------------
|
-- ----------------------------------------------------------------------------
|
||||||
call generateRbacRestrictedView('test_domain',
|
call generateRbacRestrictedView('test_domain',
|
||||||
'name',
|
$orderBy$
|
||||||
|
name
|
||||||
|
$orderBy$,
|
||||||
$updates$
|
$updates$
|
||||||
version = new.version,
|
version = new.version,
|
||||||
packageUuid = new.packageUuid,
|
packageUuid = new.packageUuid,
|
||||||
@ -222,4 +236,3 @@ call generateRbacRestrictedView('test_domain',
|
|||||||
$updates$);
|
$updates$);
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac contact
|
### rbac contact
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-14T09:00:15.762621659.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-14T09:00:15.769718298.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -109,26 +109,16 @@ create or replace function hs_office_contact_global_insert_tf()
|
|||||||
strict as $$
|
strict as $$
|
||||||
begin
|
begin
|
||||||
call grantPermissionToRole(
|
call grantPermissionToRole(
|
||||||
globalGuest(),
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_contact'),
|
||||||
createPermission(NEW.uuid, 'INSERT', 'hs_office_contact'));
|
globalGuest());
|
||||||
return NEW;
|
return NEW;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
|
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
|
||||||
create trigger z_hs_office_contact_global_insert_tg
|
create trigger z_hs_office_contact_global_insert_tg
|
||||||
after insert on global
|
after insert on global
|
||||||
for each row
|
for each row
|
||||||
execute procedure hs_office_contact_global_insert_tf();
|
execute procedure hs_office_contact_global_insert_tf();
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to insert a row to hs_office_contact.
|
|
||||||
*/
|
|
||||||
create or replace function hs_office_contact_insert_permission_missing_tf()
|
|
||||||
returns trigger
|
|
||||||
language plpgsql as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] insert into hs_office_contact not allowed for current subjects % (%)',
|
|
||||||
currentSubjects(), currentSubjectsUuids();
|
|
||||||
end; $$;
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac person
|
### rbac person
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-18T13:35:44.716916229.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-18T13:35:44.726508114.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -142,15 +142,6 @@ call generateRbacRestrictedView('hs_office_person',
|
|||||||
tradeName = new.tradeName,
|
tradeName = new.tradeName,
|
||||||
givenName = new.givenName,
|
givenName = new.givenName,
|
||||||
familyName = new.familyName
|
familyName = new.familyName
|
||||||
$updates$
|
$updates$);
|
||||||
,
|
|
||||||
$columns$
|
|
||||||
uuid,
|
|
||||||
personType,
|
|
||||||
tradeName,
|
|
||||||
givenName,
|
|
||||||
familyName
|
|
||||||
$columns$
|
|
||||||
);
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac relation
|
### rbac relation
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-15T17:17:00.854621634.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-15T17:17:00.864301165.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -65,21 +65,21 @@ begin
|
|||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeRelationAgent(NEW),
|
hsOfficeRelationAgent(NEW),
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
hsOfficePersonAdmin(newHolderPerson),
|
hsOfficeRelationAdmin(NEW),
|
||||||
hsOfficeRelationAdmin(NEW)]
|
hsOfficePersonAdmin(newHolderPerson)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
hsOfficeRelationTenant(NEW),
|
hsOfficeRelationTenant(NEW),
|
||||||
permissions => array['SELECT'],
|
permissions => array['SELECT'],
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
hsOfficeRelationAgent(NEW),
|
hsOfficePersonAdmin(newHolderPerson),
|
||||||
hsOfficeContactAdmin(newContact),
|
hsOfficeContactAdmin(newContact),
|
||||||
hsOfficePersonAdmin(newHolderPerson)],
|
hsOfficeRelationAgent(NEW)],
|
||||||
outgoingSubRoles => array[
|
outgoingSubRoles => array[
|
||||||
hsOfficeContactReferrer(newContact),
|
|
||||||
hsOfficePersonReferrer(newHolderPerson),
|
hsOfficePersonReferrer(newHolderPerson),
|
||||||
hsOfficePersonReferrer(newAnchorPerson)]
|
hsOfficePersonReferrer(newAnchorPerson),
|
||||||
|
hsOfficeContactReferrer(newContact)]
|
||||||
);
|
);
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
@ -220,34 +220,30 @@ begin
|
|||||||
return NEW;
|
return NEW;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
|
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
|
||||||
create trigger z_hs_office_relation_hs_office_person_insert_tg
|
create trigger z_hs_office_relation_hs_office_person_insert_tg
|
||||||
after insert on hs_office_person
|
after insert on hs_office_person
|
||||||
for each row
|
for each row
|
||||||
execute procedure hs_office_relation_hs_office_person_insert_tf();
|
execute procedure hs_office_relation_hs_office_person_insert_tf();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to hs_office_relation.
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_relation,
|
||||||
|
where the check is performed by a direct role.
|
||||||
|
|
||||||
|
A direct role is a role depending on a foreign key directly available in the NEW row.
|
||||||
*/
|
*/
|
||||||
create or replace function hs_office_relation_insert_permission_missing_tf()
|
create or replace function hs_office_relation_insert_permission_missing_tf()
|
||||||
returns trigger
|
returns trigger
|
||||||
language plpgsql as $$
|
language plpgsql as $$
|
||||||
begin
|
begin
|
||||||
if ( not hasInsertPermission(
|
raise exception '[403] insert into hs_office_relation not allowed for current subjects % (%)',
|
||||||
( SELECT anchorPerson.uuid FROM
|
|
||||||
|
|
||||||
(select * from hs_office_person as p where p.uuid = NEW.anchorUuid) AS anchorPerson
|
|
||||||
|
|
||||||
), 'INSERT', 'hs_office_relation') ) then
|
|
||||||
raise exception
|
|
||||||
'[403] insert into hs_office_relation not allowed for current subjects % (%)',
|
|
||||||
currentSubjects(), currentSubjectsUuids();
|
currentSubjects(), currentSubjectsUuids();
|
||||||
end if;
|
|
||||||
return NEW;
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
create trigger hs_office_relation_insert_permission_check_tg
|
create trigger hs_office_relation_insert_permission_check_tg
|
||||||
before insert on hs_office_relation
|
before insert on hs_office_relation
|
||||||
for each row
|
for each row
|
||||||
|
when ( not hasInsertPermission(NEW.anchorUuid, 'INSERT', 'hs_office_relation') )
|
||||||
execute procedure hs_office_relation_insert_permission_missing_tf();
|
execute procedure hs_office_relation_insert_permission_missing_tf();
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac partner
|
### rbac partner
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-18T09:31:47.361311186.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-18T09:31:47.368892199.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -131,36 +131,6 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
|
|
||||||
-- raise exception 'RBAC updated from rel % to %', OLD.partnerReluuid, NEW.partnerReluuid;
|
|
||||||
end; $$;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
create or replace procedure updateRbacRulesForHsOfficePartnerX(
|
|
||||||
OLD hs_office_partner,
|
|
||||||
NEW hs_office_partner
|
|
||||||
)
|
|
||||||
language plpgsql as $$
|
|
||||||
declare
|
|
||||||
partnerRel hs_office_relation;
|
|
||||||
grantCount int;
|
|
||||||
|
|
||||||
begin
|
|
||||||
assert OLD.uuid = NEW.uuid, 'uuid did change, but should not';
|
|
||||||
assert OLD.partnerReluuid <> NEW.partnerReluuid, 'partnerReluuid did not change, but should have';
|
|
||||||
|
|
||||||
delete from rbacgrants where grantedbytriggerof = OLD.uuid;
|
|
||||||
select count(*) from rbacgrants where grantedbytriggerof=NEW.uuid into grantCount;
|
|
||||||
assert grantCount=0, format('unexpected grantCount>0: %d', grantCount);
|
|
||||||
|
|
||||||
call buildRbacSystemForHsOfficePartner(NEW);
|
|
||||||
select * from hs_office_relation where uuid=NEW.partnerReluuid into partnerRel;
|
|
||||||
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), hsOfficeRelationTenant(partnerRel));
|
|
||||||
select count(*) from rbacgrants where grantedbytriggerof=NEW.uuid into grantCount;
|
|
||||||
assert grantCount>0, format('unexpected grantCount=0: %d', grantCount);
|
|
||||||
raise warning 'WARNING grantCount=%', grantCount;
|
|
||||||
|
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -172,7 +142,7 @@ create or replace function updateTriggerForHsOfficePartner_tf()
|
|||||||
language plpgsql
|
language plpgsql
|
||||||
strict as $$
|
strict as $$
|
||||||
begin
|
begin
|
||||||
call updateRbacRulesForHsOfficePartnerX(OLD, NEW);
|
call updateRbacRulesForHsOfficePartner(OLD, NEW);
|
||||||
return NEW;
|
return NEW;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
@ -228,7 +198,8 @@ create trigger z_hs_office_partner_global_insert_tg
|
|||||||
execute procedure hs_office_partner_global_insert_tf();
|
execute procedure hs_office_partner_global_insert_tf();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to hs_office_partner.
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_partner,
|
||||||
|
where only global-admin has that permission.
|
||||||
*/
|
*/
|
||||||
create or replace function hs_office_partner_insert_permission_missing_tf()
|
create or replace function hs_office_partner_insert_permission_missing_tf()
|
||||||
returns trigger
|
returns trigger
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac partnerDetails
|
### rbac partnerDetails
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-16T12:04:37.309540020.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-16T12:04:37.319601283.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -102,7 +102,8 @@ create trigger z_hs_office_partner_details_global_insert_tg
|
|||||||
execute procedure hs_office_partner_details_global_insert_tf();
|
execute procedure hs_office_partner_details_global_insert_tf();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to hs_office_partner_details.
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_partner_details,
|
||||||
|
where only global-admin has that permission.
|
||||||
*/
|
*/
|
||||||
create or replace function hs_office_partner_details_insert_permission_missing_tf()
|
create or replace function hs_office_partner_details_insert_permission_missing_tf()
|
||||||
returns trigger
|
returns trigger
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac bankAccount
|
### rbac bankAccount
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-14T08:55:11.118624882.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-14T08:55:11.127959896.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -109,26 +109,16 @@ create or replace function hs_office_bankaccount_global_insert_tf()
|
|||||||
strict as $$
|
strict as $$
|
||||||
begin
|
begin
|
||||||
call grantPermissionToRole(
|
call grantPermissionToRole(
|
||||||
globalGuest(),
|
createPermission(NEW.uuid, 'INSERT', 'hs_office_bankaccount'),
|
||||||
createPermission(NEW.uuid, 'INSERT', 'hs_office_bankaccount'));
|
globalGuest());
|
||||||
return NEW;
|
return NEW;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
|
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist
|
||||||
create trigger z_hs_office_bankaccount_global_insert_tg
|
create trigger z_hs_office_bankaccount_global_insert_tg
|
||||||
after insert on global
|
after insert on global
|
||||||
for each row
|
for each row
|
||||||
execute procedure hs_office_bankaccount_global_insert_tf();
|
execute procedure hs_office_bankaccount_global_insert_tf();
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if the user or assumed roles are allowed to insert a row to hs_office_bankaccount.
|
|
||||||
*/
|
|
||||||
create or replace function hs_office_bankaccount_insert_permission_missing_tf()
|
|
||||||
returns trigger
|
|
||||||
language plpgsql as $$
|
|
||||||
begin
|
|
||||||
raise exception '[403] insert into hs_office_bankaccount not allowed for current subjects % (%)',
|
|
||||||
currentSubjects(), currentSubjectsUuids();
|
|
||||||
end; $$;
|
|
||||||
--//
|
--//
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac sepaMandate
|
### rbac sepaMandate
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-18T16:07:14.011240343.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-18T16:07:14.019894954.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -64,8 +64,8 @@ begin
|
|||||||
hsOfficeSepaMandateAgent(NEW),
|
hsOfficeSepaMandateAgent(NEW),
|
||||||
incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW)],
|
incomingSuperRoles => array[hsOfficeSepaMandateAdmin(NEW)],
|
||||||
outgoingSubRoles => array[
|
outgoingSubRoles => array[
|
||||||
hsOfficeRelationAgent(newDebitorRel),
|
hsOfficeBankAccountReferrer(newBankAccount),
|
||||||
hsOfficeBankAccountReferrer(newBankAccount)]
|
hsOfficeRelationAgent(newDebitorRel)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
@ -146,7 +146,10 @@ create trigger z_hs_office_sepamandate_hs_office_relation_insert_tg
|
|||||||
execute procedure hs_office_sepamandate_hs_office_relation_insert_tf();
|
execute procedure hs_office_sepamandate_hs_office_relation_insert_tf();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to hs_office_sepamandate.
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_sepamandate,
|
||||||
|
where the check is performed by an indirect role.
|
||||||
|
|
||||||
|
An indirect role is a role FIXME.
|
||||||
*/
|
*/
|
||||||
create or replace function hs_office_sepamandate_insert_permission_missing_tf()
|
create or replace function hs_office_sepamandate_insert_permission_missing_tf()
|
||||||
returns trigger
|
returns trigger
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac debitor
|
### rbac debitor
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-16T13:52:18.484919583.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-20T13:55:16.722860098.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -177,7 +177,8 @@ create trigger z_hs_office_debitor_global_insert_tg
|
|||||||
execute procedure hs_office_debitor_global_insert_tf();
|
execute procedure hs_office_debitor_global_insert_tf();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to hs_office_debitor.
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_debitor,
|
||||||
|
where only global-admin has that permission.
|
||||||
*/
|
*/
|
||||||
create or replace function hs_office_debitor_insert_permission_missing_tf()
|
create or replace function hs_office_debitor_insert_permission_missing_tf()
|
||||||
returns trigger
|
returns trigger
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
### rbac membership
|
### rbac membership
|
||||||
|
|
||||||
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-21T17:09:08.826781619.
|
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
%%{init:{'flowchart':{'htmlLabels':false}}}%%
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
--liquibase formatted sql
|
--liquibase formatted sql
|
||||||
-- This code generated was by RbacViewPostgresGenerator at 2024-03-21T17:09:08.832004329.
|
-- This code generated was by RbacViewPostgresGenerator, do not amend manually.
|
||||||
|
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
@ -54,8 +54,8 @@ begin
|
|||||||
hsOfficeMembershipAdmin(NEW),
|
hsOfficeMembershipAdmin(NEW),
|
||||||
permissions => array['UPDATE'],
|
permissions => array['UPDATE'],
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
hsOfficeMembershipOwner(NEW),
|
hsOfficeRelationAgent(newPartnerRel),
|
||||||
hsOfficeRelationAgent(newPartnerRel)]
|
hsOfficeMembershipOwner(NEW)]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
@ -133,7 +133,10 @@ create trigger z_hs_office_membership_hs_office_relation_insert_tg
|
|||||||
execute procedure hs_office_membership_hs_office_relation_insert_tf();
|
execute procedure hs_office_membership_hs_office_relation_insert_tf();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the user or assumed roles are allowed to insert a row to hs_office_membership.
|
Checks if the user or assumed roles are allowed to insert a row to hs_office_membership,
|
||||||
|
where the check is performed by an indirect role.
|
||||||
|
|
||||||
|
An indirect role is a role FIXME.
|
||||||
*/
|
*/
|
||||||
create or replace function hs_office_membership_insert_permission_missing_tf()
|
create or replace function hs_office_membership_insert_permission_missing_tf()
|
||||||
returns trigger
|
returns trigger
|
||||||
|
@ -4,8 +4,9 @@ spring:
|
|||||||
platform: postgres
|
platform: postgres
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers
|
url-tc: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers
|
||||||
url-local: jdbc:postgresql://localhost:5432/postgres
|
url-local: jdbc:postgresql://localhost:5432/postgres
|
||||||
|
url: ${spring.datasource.url-tc}
|
||||||
username: postgres
|
username: postgres
|
||||||
password: password
|
password: password
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user