generated BankAccount RBAC rules, BankAccount tests green again

This commit is contained in:
Michael Hoennig 2024-03-14 06:22:53 +01:00
parent 2774707801
commit 6b68b93082
10 changed files with 144 additions and 131 deletions

View File

@ -59,7 +59,7 @@ public class HsOfficeBankAccountEntity implements HasUuid, Stringifyable {
public static RbacView rbac() { public static RbacView rbac() {
return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class) return rbacViewFor("bankAccount", HsOfficeBankAccountEntity.class)
.withIdentityView(SQL.projection("concat(iban, ':', holder)")) .withIdentityView(SQL.projection("iban"))
.withUpdatableColumns("holder", "iban", "bic") .withUpdatableColumns("holder", "iban", "bic")
.toRole("global", GUEST).grantPermission("bankAccount", INSERT) .toRole("global", GUEST).grantPermission("bankAccount", INSERT)

View File

@ -75,10 +75,11 @@ public class HsOfficeContactEntity implements Stringifyable, HasUuid {
}) })
.createSubRole(REFERRER, (with) -> { .createSubRole(REFERRER, (with) -> {
with.permission(SELECT); with.permission(SELECT);
}); })
.toRole(GLOBAL, GUEST).grantPermission("contact", INSERT);
} }
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
rbac().generateWithBaseFileName("203-hs-office-contact-rbac-generated"); rbac().generateWithBaseFileName("203-hs-office-contact-rbac");
} }
} }

View File

@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.hs.office.partner;
import lombok.*; import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity;
import net.hostsharing.hsadminng.persistence.HasUuid; import net.hostsharing.hsadminng.persistence.HasUuid;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
@ -14,10 +13,8 @@ import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
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.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.rbacViewFor; import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.rbacViewFor;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify; import static net.hostsharing.hsadminng.stringify.Stringify.stringify;

View File

@ -318,12 +318,12 @@ class RolesGrantsAndPermissionsGenerator {
generatePermissionsForRole(plPgSql, role); generatePermissionsForRole(plPgSql, role);
generateUserGrantsForRole(plPgSql, role);
generateIncomingSuperRolesForRole(plPgSql, role); generateIncomingSuperRolesForRole(plPgSql, role);
generateOutgoingSubRolesForRole(plPgSql, role); generateOutgoingSubRolesForRole(plPgSql, role);
generateUserGrantsForRole(plPgSql, role);
plPgSql.chopTail(",\n"); plPgSql.chopTail(",\n");
plPgSql.writeLn(); plPgSql.writeLn();
}); });

View File

@ -37,7 +37,7 @@ declare
subRoleUuid uuid; subRoleUuid uuid;
superRoleUuid uuid; superRoleUuid uuid;
userUuid uuid; userUuid uuid;
grantedByRoleUuid uuid; grantedByRoleUuid uuid; -- FIXME: rename to userGrantsByRoleUuid
begin begin
roleUuid := createRole(roleDescriptor); roleUuid := createRole(roleDescriptor);
@ -58,8 +58,9 @@ begin
end loop; end loop;
if cardinality(userUuids) > 0 then if cardinality(userUuids) > 0 then
-- direct grants to users need a grantedByRole which can revoke the grant
if grantedByRole is null then if grantedByRole is null then
grantedByRoleUuid := roleUuid; grantedByRoleUuid := roleUuid; -- FIXME: or do we want to require an explicit grantedByRoleUuid?
else else
grantedByRoleUuid := getRoleId(grantedByRole); grantedByRoleUuid := getRoleId(grantedByRole);
end if; end if;

View File

@ -1,4 +1,6 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-14T09:00:15.769718298.
-- ============================================================================ -- ============================================================================
--changeset hs-office-contact-rbac-OBJECT:1 endDelimiter:--// --changeset hs-office-contact-rbac-OBJECT:1 endDelimiter:--//
@ -15,28 +17,28 @@ call generateRbacRoleDescriptors('hsOfficeContact', 'hs_office_contact');
-- ============================================================================ -- ============================================================================
--changeset hs-office-contact-rbac-ROLES-CREATION:1 endDelimiter:--// --changeset hs-office-contact-rbac-insert-trigger:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
/* /*
Creates the roles and their assignments for a new contact for the AFTER INSERT TRIGGER. Creates the roles, grants and permission for the AFTER INSERT TRIGGER.
*/ */
create or replace function createRbacRolesForHsOfficeContact() create or replace procedure buildRbacSystemForHsOfficeContact(
returns trigger NEW hs_office_contact
language plpgsql )
strict as $$ language plpgsql as $$
declare
begin begin
if TG_OP <> 'INSERT' then call enterTriggerForObjectUuid(NEW.uuid);
raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if;
perform createRoleWithGrants( perform createRoleWithGrants(
hsOfficeContactOwner(NEW), hsOfficeContactOwner(NEW),
permissions => array['DELETE'], permissions => array['DELETE'],
incomingSuperRoles => array[globalAdmin()], incomingSuperRoles => array[globalAdmin()],
userUuids => array[currentUserUuid()], userUuids => array[currentUserUuid()]
grantedByRole => globalAdmin()
); );
perform createRoleWithGrants( perform createRoleWithGrants(
@ -51,86 +53,105 @@ begin
incomingSuperRoles => array[hsOfficeContactAdmin(NEW)] incomingSuperRoles => array[hsOfficeContactAdmin(NEW)]
); );
return NEW; call leaveTriggerForObjectUuid(NEW.uuid);
end; $$; end; $$;
/* /*
An AFTER INSERT TRIGGER which creates the role structure for a new customer. AFTER INSERT TRIGGER to create the role+grant structure for a new hs_office_contact row.
*/ */
create trigger createRbacRolesForHsOfficeContact_Trigger create or replace function insertTriggerForHsOfficeContact_tf()
after insert returns trigger
on hs_office_contact language plpgsql
strict as $$
begin
call buildRbacSystemForHsOfficeContact(NEW);
return NEW;
end; $$;
create trigger insertTriggerForHsOfficeContact_tg
after insert on hs_office_contact
for each row for each row
execute procedure createRbacRolesForHsOfficeContact(); execute procedure insertTriggerForHsOfficeContact_tf();
--// --//
-- ============================================================================
--changeset hs-office-contact-rbac-INSERT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates INSERT INTO hs_office_contact permissions for the related global rows.
*/
do language plpgsql $$
declare
row global;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO hs_office_contact permissions for the related global rows');
FOR row IN SELECT * FROM global
LOOP
roleUuid := findRoleId(globalGuest());
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_contact');
call grantPermissionToRole(permissionUuid, roleUuid);
END LOOP;
END;
$$;
/**
Adds hs_office_contact INSERT permission to specified role of new global rows.
*/
create or replace function hs_office_contact_global_insert_tf()
returns trigger
language plpgsql
strict as $$
begin
call grantPermissionToRole(
globalGuest(),
createPermission(NEW.uuid, 'INSERT', 'hs_office_contact'));
return NEW;
end; $$;
create trigger hs_office_contact_global_insert_tg
after insert on global
for each row
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; $$;
--//
-- ============================================================================ -- ============================================================================
--changeset hs-office-contact-rbac-IDENTITY-VIEW:1 endDelimiter:--// --changeset hs-office-contact-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacIdentityViewFromProjection('hs_office_contact', $idName$ call generateRbacIdentityViewFromProjection('hs_office_contact', $idName$
target.label label
$idName$); $idName$);
--// --//
-- ============================================================================ -- ============================================================================
--changeset hs-office-contact-rbac-RESTRICTED-VIEW:1 endDelimiter:--// --changeset hs-office-contact-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacRestrictedView('hs_office_contact', 'target.label', call generateRbacRestrictedView('hs_office_contact',
$orderBy$
label
$orderBy$,
$updates$ $updates$
label = new.label, label = new.label,
postalAddress = new.postalAddress, postalAddress = new.postalAddress,
emailAddresses = new.emailAddresses, emailAddresses = new.emailAddresses,
phoneNumbers = new.phoneNumbers phoneNumbers = new.phoneNumbers
$updates$); $updates$);
--/
-- ============================================================================
--changeset hs-office-contact-rbac-NEW-CONTACT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates a global permission for new-contact and assigns it to the hostsharing admins role.
*/
do language plpgsql $$
declare
addCustomerPermissions uuid[];
globalObjectUuid uuid;
globalAdminRoleUuid uuid;
begin
call defineContext('granting global new-contact permission to global admin role', null, null, null);
globalAdminRoleUuid := findRoleId(globalAdmin());
globalObjectUuid := (select uuid from global);
addCustomerPermissions := createPermissions(globalObjectUuid, array ['new-contact']);
call grantPermissionsToRole(globalAdminRoleUuid, addCustomerPermissions);
end;
$$;
/**
Used by the trigger to prevent the add-customer to current user respectively assumed roles.
*/
create or replace function addHsOfficeContactNotAllowedForCurrentSubjects()
returns trigger
language PLPGSQL
as $$
begin
raise exception '[403] new-contact not permitted for %',
array_to_string(currentSubjects(), ';', 'null');
end; $$;
/**
Checks if the user or assumed roles are allowed to create a new customer.
*/
create trigger hs_office_contact_insert_trigger
before insert
on hs_office_contact
for each row
-- TODO.spec: who is allowed to create new contacts
when ( not hasAssumedRole() )
execute procedure addHsOfficeContactNotAllowedForCurrentSubjects();
--// --//

View File

@ -1,6 +1,6 @@
### rbac bankAccount ### rbac bankAccount
This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-11T19:09:38.350576842. This code generated was by RbacViewMermaidFlowchartGenerator at 2024-03-14T08:55:11.118624882.
```mermaid ```mermaid
%%{init:{'flowchart':{'htmlLabels':false}}}%% %%{init:{'flowchart':{'htmlLabels':false}}}%%

View File

@ -1,5 +1,6 @@
--liquibase formatted sql --liquibase formatted sql
-- This code generated was by RbacViewPostgresGenerator at 2024-03-11T19:09:38.359318650. -- This code generated was by RbacViewPostgresGenerator at 2024-03-14T08:55:11.127959896.
-- ============================================================================ -- ============================================================================
--changeset hs-office-bankaccount-rbac-OBJECT:1 endDelimiter:--// --changeset hs-office-bankaccount-rbac-OBJECT:1 endDelimiter:--//
@ -36,8 +37,8 @@ begin
perform createRoleWithGrants( perform createRoleWithGrants(
hsOfficeBankAccountOwner(NEW), hsOfficeBankAccountOwner(NEW),
permissions => array['DELETE'], permissions => array['DELETE'],
userUuids => array[currentUserUuid()], incomingSuperRoles => array[globalAdmin()],
incomingSuperRoles => array[globalAdmin()] userUuids => array[currentUserUuid()]
); );
perform createRoleWithGrants( perform createRoleWithGrants(
@ -72,9 +73,9 @@ create trigger insertTriggerForHsOfficeBankAccount_tg
after insert on hs_office_bankaccount after insert on hs_office_bankaccount
for each row for each row
execute procedure insertTriggerForHsOfficeBankAccount_tf(); execute procedure insertTriggerForHsOfficeBankAccount_tf();
--// --//
-- ============================================================================ -- ============================================================================
--changeset hs-office-bankaccount-rbac-INSERT:1 endDelimiter:--// --changeset hs-office-bankaccount-rbac-INSERT:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
@ -108,8 +109,8 @@ create or replace function hs_office_bankaccount_global_insert_tf()
strict as $$ strict as $$
begin begin
call grantPermissionToRole( call grantPermissionToRole(
createPermission(NEW.uuid, 'INSERT', 'hs_office_bankaccount'), globalGuest(),
globalGuest()); createPermission(NEW.uuid, 'INSERT', 'hs_office_bankaccount'));
return NEW; return NEW;
end; $$; end; $$;
@ -128,23 +129,23 @@ begin
raise exception '[403] insert into hs_office_bankaccount not allowed for current subjects % (%)', raise exception '[403] insert into hs_office_bankaccount not allowed for current subjects % (%)',
currentSubjects(), currentSubjectsUuids(); currentSubjects(), currentSubjectsUuids();
end; $$; end; $$;
--// --//
-- ============================================================================ -- ============================================================================
--changeset hs-office-bankaccount-rbac-IDENTITY-VIEW:1 endDelimiter:--// --changeset hs-office-bankaccount-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacIdentityViewFromProjection('hs_office_bankaccount', $idName$ call generateRbacIdentityViewFromProjection('hs_office_bankaccount', $idName$
concat(iban, ':', holder) iban
$idName$); $idName$);
--// --//
-- ============================================================================ -- ============================================================================
--changeset hs-office-bankaccount-rbac-RESTRICTED-VIEW:1 endDelimiter:--// --changeset hs-office-bankaccount-rbac-RESTRICTED-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRbacRestrictedView('hs_office_bankaccount', call generateRbacRestrictedView('hs_office_bankaccount',
$orderBy$ $orderBy$
concat(iban, ':', holder) iban
$orderBy$, $orderBy$,
$updates$ $updates$
holder = new.holder, holder = new.holder,
@ -153,4 +154,3 @@ call generateRbacRestrictedView('hs_office_bankaccount',
$updates$); $updates$);
--// --//

View File

@ -102,23 +102,21 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTestWithC
final var roles = rawRoleRepo.findAll(); final var roles = rawRoleRepo.findAll();
assertThat(distinctRoleNamesOf(roles)).containsExactlyInAnyOrder(Array.from( assertThat(distinctRoleNamesOf(roles)).containsExactlyInAnyOrder(Array.from(
initialRoleNames, initialRoleNames,
"hs_office_bankaccount#sometempaccC.owner", "hs_office_bankaccount#DE25500105176934832579.owner",
"hs_office_bankaccount#sometempaccC.admin", "hs_office_bankaccount#DE25500105176934832579.admin",
"hs_office_bankaccount#sometempaccC.tenant", "hs_office_bankaccount#DE25500105176934832579.referrer"
"hs_office_bankaccount#sometempaccC.guest"
)); ));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted( assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, initialGrantNames,
"{ grant perm DELETE on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.owner by system and assume }", "{ grant perm DELETE on hs_office_bankaccount#DE25500105176934832579 to role hs_office_bankaccount#DE25500105176934832579.owner by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.owner to role global#global.admin by system and assume }", "{ grant role hs_office_bankaccount#DE25500105176934832579.owner to role global#global.admin by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.owner to user selfregistered-user-drew@hostsharing.org by global#global.admin and assume }", "{ grant role hs_office_bankaccount#DE25500105176934832579.owner to user selfregistered-user-drew@hostsharing.org by hs_office_bankaccount#DE25500105176934832579.owner and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.admin to role hs_office_bankaccount#sometempaccC.owner by system and assume }", "{ grant role hs_office_bankaccount#DE25500105176934832579.admin to role hs_office_bankaccount#DE25500105176934832579.owner by system and assume }",
"{ grant perm UPDATE on hs_office_bankaccount#DE25500105176934832579 to role hs_office_bankaccount#DE25500105176934832579.admin by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.tenant to role hs_office_bankaccount#sometempaccC.admin by system and assume }", "{ grant perm SELECT on hs_office_bankaccount#DE25500105176934832579 to role hs_office_bankaccount#DE25500105176934832579.referrer by system and assume }",
"{ grant role hs_office_bankaccount#DE25500105176934832579.referrer to role hs_office_bankaccount#DE25500105176934832579.admin by system and assume }",
"{ grant perm SELECT on hs_office_bankaccount#sometempaccC to role hs_office_bankaccount#sometempaccC.guest by system and assume }",
"{ grant role hs_office_bankaccount#sometempaccC.guest to role hs_office_bankaccount#sometempaccC.tenant by system and assume }",
null null
)); ));
} }
@ -241,10 +239,6 @@ class HsOfficeBankAccountRepositoryIntegrationTest extends ContextBasedTestWithC
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll()); final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll()); final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll());
final var givenBankAccount = givenSomeTemporaryBankAccount("selfregistered-user-drew@hostsharing.org"); final var givenBankAccount = givenSomeTemporaryBankAccount("selfregistered-user-drew@hostsharing.org");
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll()).size()).as("unexpected number of roles created")
.isEqualTo(initialRoleNames.size() + 4);
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()).size()).as("unexpected number of grants created")
.isEqualTo(initialGrantNames.size() + 7);
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {

View File

@ -107,12 +107,11 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTestWithClean
"hs_office_contact#anothernewcontact.admin", "hs_office_contact#anothernewcontact.admin",
"hs_office_contact#anothernewcontact.referrer" "hs_office_contact#anothernewcontact.referrer"
)); ));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.from( assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, initialGrantNames,
"{ grant perm * on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.owner to role global#global.admin by system and assume }", "{ grant role hs_office_contact#anothernewcontact.owner to role global#global.admin by system and assume }",
"{ grant perm UPDATE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.admin by system and assume }", "{ grant perm UPDATE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.admin by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.tenant to role hs_office_contact#anothernewcontact.admin by system and assume }", "{ grant role hs_office_contact#anothernewcontact.owner to user selfregistered-user-drew@hostsharing.org by system and assume }",
"{ grant perm DELETE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }", "{ grant perm DELETE on hs_office_contact#anothernewcontact to role hs_office_contact#anothernewcontact.owner by system and assume }",
"{ grant role hs_office_contact#anothernewcontact.admin to role hs_office_contact#anothernewcontact.owner by system and assume }", "{ grant role hs_office_contact#anothernewcontact.admin to role hs_office_contact#anothernewcontact.owner by system and assume }",