fix insert grants + assertions and improve generated formatting

This commit is contained in:
Michael Hoennig 2024-03-27 09:30:59 +01:00
parent 3872f5dc19
commit 1f59462f1b
20 changed files with 76 additions and 116 deletions

View File

@ -138,7 +138,7 @@ public class HsOfficeMembershipEntity implements HasUuid, Stringifyable {
WHERE partner.uuid = ${REF}.partnerUuid
"""),
NOT_NULL)
.toRole("partnerRel", ADMIN).grantPermission(INSERT)
.toRole("global", ADMIN).grantPermission(INSERT)
.createRole(OWNER, (with) -> {
with.owningUser(CREATOR);

View File

@ -47,16 +47,14 @@ public class InsertTriggerGenerator {
do language plpgsql $$
declare
row ${rawSuperTableName};
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO ${rawSubTableName} permissions for the related ${rawSuperTableName} rows');
FOR row IN SELECT * FROM ${rawSuperTableName}
LOOP
roleUuid := findRoleId(${rawSuperRoleDescriptor});
permissionUuid := createPermission(row.uuid, 'INSERT', '${rawSubTableName}');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', '${rawSubTableName}'),
${rawSuperRoleDescriptor});
END LOOP;
END;
$$;

View File

@ -63,6 +63,7 @@ create or replace view rbacgrants_ev as
x.grantedByRoleUuid,
x.ascendantUuid as ascendantUuid,
x.descendantUuid as descendantUuid,
x.op as permOp, x.optablename as permOpTableName,
x.assumed
from (
select g.uuid as grantUuid,
@ -74,13 +75,17 @@ create or replace view rbacgrants_ev as
'role ' || aro.objectTable || '#' || findIdNameByObjectUuid(aro.objectTable, aro.uuid) || '.' || ar.roletype
) as ascendingIdName,
aro.objectTable, aro.uuid,
coalesce(
'role ' || dro.objectTable || '#' || findIdNameByObjectUuid(dro.objectTable, dro.uuid) || '.' || dr.roletype,
'perm ' || dp.op || ' on ' || dpo.objecttable || '#' || findIdNameByObjectUuid(dpo.objectTable, dpo.uuid)
( case
when dro is not null
then ('role ' || dro.objectTable || '#' || findIdNameByObjectUuid(dro.objectTable, dro.uuid) || '.' || dr.roletype)
when dp.op = 'INSERT'
then 'perm ' || dp.op || ' into ' || dp.opTableName || ' with ' || dpo.objecttable || '#' || findIdNameByObjectUuid(dpo.objectTable, dpo.uuid)
else 'perm ' || dp.op || ' on ' || dpo.objecttable || '#' || findIdNameByObjectUuid(dpo.objectTable, dpo.uuid)
end
) as descendingIdName,
dro.objectTable, dro.uuid
from rbacgrants as g
dro.objectTable, dro.uuid,
dp.op, dp.optablename
from rbacgrants as g
left outer join rbacrole as ar on ar.uuid = g.ascendantUuid
left outer join rbacobject as aro on aro.uuid = ar.objectuuid

View File

@ -86,16 +86,14 @@ execute procedure insertTriggerForTestCustomer_tf();
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);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'test_customer'),
globalAdmin());
END LOOP;
END;
$$;

View File

@ -151,16 +151,14 @@ execute procedure updateTriggerForTestPackage_tf();
do language plpgsql $$
declare
row test_customer;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO test_package permissions for the related test_customer rows');
FOR row IN SELECT * FROM test_customer
LOOP
roleUuid := findRoleId(testCustomerAdmin(row));
permissionUuid := createPermission(row.uuid, 'INSERT', 'test_package');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'test_package'),
testCustomerAdmin(row));
END LOOP;
END;
$$;

View File

@ -150,16 +150,14 @@ execute procedure updateTriggerForTestDomain_tf();
do language plpgsql $$
declare
row test_package;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO test_domain permissions for the related test_package rows');
FOR row IN SELECT * FROM test_package
LOOP
roleUuid := findRoleId(testPackageAdmin(row));
permissionUuid := createPermission(row.uuid, 'INSERT', 'test_domain');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'test_domain'),
testPackageAdmin(row));
END LOOP;
END;
$$;

View File

@ -86,16 +86,14 @@ execute procedure insertTriggerForHsOfficeContact_tf();
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);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_contact'),
globalGuest());
END LOOP;
END;
$$;

View File

@ -86,16 +86,14 @@ execute procedure insertTriggerForHsOfficePerson_tf();
do language plpgsql $$
declare
row global;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO hs_office_person permissions for the related global rows');
FOR row IN SELECT * FROM global
LOOP
roleUuid := findRoleId(globalGuest());
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_person');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_person'),
globalGuest());
END LOOP;
END;
$$;

View File

@ -192,16 +192,14 @@ execute procedure updateTriggerForHsOfficeRelation_tf();
do language plpgsql $$
declare
row hs_office_person;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO hs_office_relation permissions for the related hs_office_person rows');
FOR row IN SELECT * FROM hs_office_person
LOOP
roleUuid := findRoleId(hsOfficePersonAdmin(row));
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_relation');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_relation'),
hsOfficePersonAdmin(row));
END LOOP;
END;
$$;

View File

@ -163,16 +163,14 @@ execute procedure updateTriggerForHsOfficePartner_tf();
do language plpgsql $$
declare
row global;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO hs_office_partner permissions for the related global rows');
FOR row IN SELECT * FROM global
LOOP
roleUuid := findRoleId(globalAdmin());
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_partner');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_partner'),
globalAdmin());
END LOOP;
END;
$$;

View File

@ -67,16 +67,14 @@ execute procedure insertTriggerForHsOfficePartnerDetails_tf();
do language plpgsql $$
declare
row global;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO hs_office_partner_details permissions for the related global rows');
FOR row IN SELECT * FROM global
LOOP
roleUuid := findRoleId(globalAdmin());
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_partner_details');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_partner_details'),
globalAdmin());
END LOOP;
END;
$$;

View File

@ -86,16 +86,14 @@ execute procedure insertTriggerForHsOfficeBankAccount_tf();
do language plpgsql $$
declare
row global;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO hs_office_bankaccount permissions for the related global rows');
FOR row IN SELECT * FROM global
LOOP
roleUuid := findRoleId(globalGuest());
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_bankaccount');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_bankaccount'),
globalGuest());
END LOOP;
END;
$$;

View File

@ -111,16 +111,14 @@ execute procedure insertTriggerForHsOfficeSepaMandate_tf();
do language plpgsql $$
declare
row hs_office_relation;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO hs_office_sepamandate permissions for the related hs_office_relation rows');
FOR row IN SELECT * FROM hs_office_relation
LOOP
roleUuid := findRoleId(hsOfficeRelationAdmin(row));
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_sepamandate');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_sepamandate'),
hsOfficeRelationAdmin(row));
END LOOP;
END;
$$;

View File

@ -136,16 +136,14 @@ execute procedure updateTriggerForHsOfficeDebitor_tf();
do language plpgsql $$
declare
row global;
permissionUuid uuid;
roleUuid uuid;
begin
call defineContext('create INSERT INTO hs_office_debitor permissions for the related global rows');
FOR row IN SELECT * FROM global
LOOP
roleUuid := findRoleId(globalAdmin());
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_debitor');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_debitor'),
globalAdmin());
END LOOP;
END;
$$;

View File

@ -151,7 +151,7 @@ role:membership:admin ==> role:membership:referrer
role:membership:referrer ==> role:partnerRel:tenant
%% granting permissions to roles
role:partnerRel:admin ==> perm:membership:INSERT
role:global:admin ==> perm:membership:INSERT
role:membership:owner ==> perm:membership:DELETE
role:membership:admin ==> perm:membership:UPDATE
role:membership:referrer ==> perm:membership:SELECT

View File

@ -93,79 +93,60 @@ execute procedure insertTriggerForHsOfficeMembership_tf();
-- ----------------------------------------------------------------------------
/*
Creates INSERT INTO hs_office_membership permissions for the related hs_office_relation rows.
Creates INSERT INTO hs_office_membership permissions for the related global rows.
*/
do language plpgsql $$
declare
row hs_office_relation;
permissionUuid uuid;
roleUuid uuid;
row global;
begin
call defineContext('create INSERT INTO hs_office_membership permissions for the related hs_office_relation rows');
call defineContext('create INSERT INTO hs_office_membership permissions for the related global rows');
FOR row IN SELECT * FROM hs_office_relation
FOR row IN SELECT * FROM global
LOOP
roleUuid := findRoleId(hsOfficeRelationAdmin(row));
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_membership');
call grantPermissionToRole(permissionUuid, roleUuid);
call grantPermissionToRole(
createPermission(row.uuid, 'INSERT', 'hs_office_membership'),
globalAdmin());
END LOOP;
END;
$$;
/**
Adds hs_office_membership INSERT permission to specified role of new hs_office_relation rows.
Adds hs_office_membership INSERT permission to specified role of new global rows.
*/
create or replace function hs_office_membership_hs_office_relation_insert_tf()
create or replace function hs_office_membership_global_insert_tf()
returns trigger
language plpgsql
strict as $$
begin
call grantPermissionToRole(
createPermission(NEW.uuid, 'INSERT', 'hs_office_membership'),
hsOfficeRelationAdmin(NEW));
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_hs_office_membership_hs_office_relation_insert_tg
after insert on hs_office_relation
create trigger z_hs_office_membership_global_insert_tg
after insert on global
for each row
execute procedure hs_office_membership_hs_office_relation_insert_tf();
execute procedure hs_office_membership_global_insert_tf();
/**
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 which depends on an object uuid which is not a direct foreign key
of the source entity, but needs to be fetched via joined tables.
where only global-admin has that permission.
*/
create or replace function hs_office_membership_insert_permission_check_tf()
create or replace function hs_office_membership_insert_permission_missing_tf()
returns trigger
language plpgsql as $$
declare
superRoleObjectUuid uuid;
begin
superRoleObjectUuid := (SELECT partnerRel.uuid
FROM hs_office_partner AS partner
JOIN hs_office_relation AS partnerRel ON partnerRel.uuid = partner.partnerRelUuid
WHERE partner.uuid = NEW.partnerUuid
);
assert superRoleObjectUuid is not null, 'superRoleObjectUuid must not be null';
if ( not hasInsertPermission(superRoleObjectUuid, 'INSERT', 'hs_office_membership') ) then
raise exception
'[403] insert into hs_office_membership not allowed for current subjects % (%)',
currentSubjects(), currentSubjectsUuids();
end if;
return NEW;
raise exception '[403] insert into hs_office_membership not allowed for current subjects % (%)',
currentSubjects(), currentSubjectsUuids();
end; $$;
create trigger hs_office_membership_insert_permission_check_tg
before insert on hs_office_membership
for each row
execute procedure hs_office_membership_insert_permission_check_tf();
when ( not isGlobalAdmin() )
execute procedure hs_office_membership_insert_permission_missing_tf();
--//
-- ============================================================================

View File

@ -179,8 +179,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
// FIXME: the next line is completely wrong, the format as well that it exists
"{ grant perm INSERT on relation#FirstGmbH-with-DEBITOR-FourtheG to role relation#FirstGmbH-with-DEBITOR-FourtheG.admin by system and assume }",
"{ grant perm INSERT into sepamandate with relation#FirstGmbH-with-DEBITOR-FourtheG to role relation#FirstGmbH-with-DEBITOR-FourtheG.admin by system and assume }",
// owner
"{ grant perm DELETE on debitor#D-1000122 to role relation#FirstGmbH-with-DEBITOR-FourtheG.owner by system and assume }",

View File

@ -142,8 +142,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(distinct(fromFormatted(
initialGrantNames,
// FIXME: this entry is wrong in existance and format
"{ grant perm INSERT on relation#HostsharingeG-with-PARTNER-EBess to role relation#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
"{ grant perm INSERT into sepamandate with relation#HostsharingeG-with-PARTNER-EBess to role relation#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
// permissions on partner
"{ grant perm DELETE on partner#P-20032 to role relation#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",

View File

@ -94,9 +94,9 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTestWithCleanu
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll());
// when
attempt(em, () -> toCleanup(personRepo.save(
hsOfficePerson("another new person")))
).assumeSuccessful();
attempt(em, () -> toCleanup(
personRepo.save(hsOfficePerson("another new person"))
)).assumeSuccessful();
// then
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(
@ -109,8 +109,7 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTestWithCleanu
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(
Array.from(
initialGrantNames,
// FIXME: the INSERT grant is wrong in format and existence
"{ grant perm INSERT on hs_office_person#anothernewperson to role hs_office_person#anothernewperson.admin by system and assume }",
"{ grant perm INSERT into hs_office_relation with hs_office_person#anothernewperson to role hs_office_person#anothernewperson.admin by system and assume }",
"{ grant role hs_office_person#anothernewperson.owner to user selfregistered-user-drew@hostsharing.org by hs_office_person#anothernewperson.owner and assume }",
"{ grant role hs_office_person#anothernewperson.owner to role global#global.admin by system and assume }",

View File

@ -131,7 +131,8 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
"hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.tenant"));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames,
"{ grant perm INSERT on hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert to role hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.admin by system and assume }",
// TODO: this grant should only be created for DEBITOR-Relationships, thus the RBAC DSL needs to support conditional grants
"{ grant perm INSERT into hs_office_sepamandate with hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert to role hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.admin by system and assume }",
"{ grant perm DELETE on hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert to role hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.owner by system and assume }",
"{ grant role hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.owner to role global#global.admin by system and assume }",