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 WHERE partner.uuid = ${REF}.partnerUuid
"""), """),
NOT_NULL) NOT_NULL)
.toRole("partnerRel", ADMIN).grantPermission(INSERT) .toRole("global", ADMIN).grantPermission(INSERT)
.createRole(OWNER, (with) -> { .createRole(OWNER, (with) -> {
with.owningUser(CREATOR); with.owningUser(CREATOR);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -151,7 +151,7 @@ role:membership:admin ==> role:membership:referrer
role:membership:referrer ==> role:partnerRel:tenant role:membership:referrer ==> role:partnerRel:tenant
%% granting permissions to roles %% granting permissions to roles
role:partnerRel:admin ==> perm:membership:INSERT role:global:admin ==> perm:membership:INSERT
role:membership:owner ==> perm:membership:DELETE role:membership:owner ==> perm:membership:DELETE
role:membership:admin ==> perm:membership:UPDATE role:membership:admin ==> perm:membership:UPDATE
role:membership:referrer ==> perm:membership:SELECT 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 $$ do language plpgsql $$
declare declare
row hs_office_relation; row global;
permissionUuid uuid;
roleUuid uuid;
begin 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 LOOP
roleUuid := findRoleId(hsOfficeRelationAdmin(row)); call grantPermissionToRole(
permissionUuid := createPermission(row.uuid, 'INSERT', 'hs_office_membership'); createPermission(row.uuid, 'INSERT', 'hs_office_membership'),
call grantPermissionToRole(permissionUuid, roleUuid); globalAdmin());
END LOOP; END LOOP;
END; 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 returns trigger
language plpgsql language plpgsql
strict as $$ strict as $$
begin begin
call grantPermissionToRole( call grantPermissionToRole(
createPermission(NEW.uuid, 'INSERT', 'hs_office_membership'), createPermission(NEW.uuid, 'INSERT', 'hs_office_membership'),
hsOfficeRelationAdmin(NEW)); globalAdmin());
return NEW; return NEW;
end; $$; end; $$;
-- z_... is to put it at the end of after insert triggers, to make sure the roles exist -- 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 create trigger z_hs_office_membership_global_insert_tg
after insert on hs_office_relation after insert on global
for each row 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, 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. where only global-admin has that permission.
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.
*/ */
create or replace function hs_office_membership_insert_permission_check_tf() create or replace function hs_office_membership_insert_permission_missing_tf()
returns trigger returns trigger
language plpgsql as $$ language plpgsql as $$
declare
superRoleObjectUuid uuid;
begin begin
superRoleObjectUuid := (SELECT partnerRel.uuid raise exception '[403] insert into hs_office_membership not allowed for current subjects % (%)',
FROM hs_office_partner AS partner currentSubjects(), currentSubjectsUuids();
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;
end; $$; end; $$;
create trigger hs_office_membership_insert_permission_check_tg create trigger hs_office_membership_insert_permission_check_tg
before insert on hs_office_membership before insert on hs_office_membership
for each row 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_", "")) .map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(Array.fromFormatted( .containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, initialGrantNames,
// FIXME: the next line is completely wrong, the format as well that it exists "{ grant perm INSERT into sepamandate with relation#FirstGmbH-with-DEBITOR-FourtheG to role relation#FirstGmbH-with-DEBITOR-FourtheG.admin by system and assume }",
"{ grant perm INSERT on relation#FirstGmbH-with-DEBITOR-FourtheG to role relation#FirstGmbH-with-DEBITOR-FourtheG.admin by system and assume }",
// owner // owner
"{ grant perm DELETE on debitor#D-1000122 to role relation#FirstGmbH-with-DEBITOR-FourtheG.owner by system and assume }", "{ 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_", "")) .map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(distinct(fromFormatted( .containsExactlyInAnyOrder(distinct(fromFormatted(
initialGrantNames, initialGrantNames,
// FIXME: this entry is wrong in existance and format "{ grant perm INSERT into sepamandate with relation#HostsharingeG-with-PARTNER-EBess to role relation#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
"{ grant perm INSERT on relation#HostsharingeG-with-PARTNER-EBess to role relation#HostsharingeG-with-PARTNER-EBess.admin by system and assume }",
// permissions on partner // permissions on partner
"{ grant perm DELETE on partner#P-20032 to role relation#HostsharingeG-with-PARTNER-EBess.admin by system and assume }", "{ 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()); final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll());
// when // when
attempt(em, () -> toCleanup(personRepo.save( attempt(em, () -> toCleanup(
hsOfficePerson("another new person"))) personRepo.save(hsOfficePerson("another new person"))
).assumeSuccessful(); )).assumeSuccessful();
// then // then
assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder( assertThat(distinctRoleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(
@ -109,8 +109,7 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTestWithCleanu
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder( assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(
Array.from( Array.from(
initialGrantNames, initialGrantNames,
// FIXME: the INSERT grant is wrong in format and existence "{ grant perm INSERT into hs_office_relation with hs_office_person#anothernewperson to role hs_office_person#anothernewperson.admin by system and assume }",
"{ grant perm INSERT on 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 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 }", "{ 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")); "hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.tenant"));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted( assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll())).containsExactlyInAnyOrder(Array.fromFormatted(
initialGrantNames, 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 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 }", "{ grant role hs_office_relation#ErbenBesslerMelBessler-with-REPRESENTATIVE-BesslerBert.owner to role global#global.admin by system and assume }",