consolidating role deletion from business objects to rbac system

This commit is contained in:
Michael Hoennig 2022-09-13 10:58:54 +02:00
parent ac5f19e399
commit 0b48e8d1b7
12 changed files with 136 additions and 263 deletions

View File

@ -122,7 +122,17 @@ create table RbacObject
call create_journal('RbacObject');
create or replace function createRbacObject()
--//
-- ============================================================================
--changeset rbac-base-GENERATE-RELATED-OBJECT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Inserts related RbacObject for use in the BEFORE ONSERT TRIGGERs on the business objects.
*/
create or replace function insertRelatedRbacObject()
returns trigger
language plpgsql
strict as $$
@ -147,8 +157,51 @@ begin
raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if;
end; $$;
/*
Deletes related RbacObject for use in the BEFORE DELETE TRIGGERs on the business objects.
*/
create or replace function deleteRelatedRbacObject()
returns trigger
language plpgsql
strict as $$
begin
if TG_OP = 'DELETE' then
delete from RbacObject where rbacobject.uuid = old.uuid;
else
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if;
return old;
end; $$;
create or replace procedure generateRelatedRbacObject(targetTable varchar)
language plpgsql as $$
declare
createInsertTriggerSQL text;
createDeleteTriggerSQL text;
begin
createInsertTriggerSQL = format($sql$
create trigger createRbacObjectFor_%s_Trigger
before insert
on %s
for each row
execute procedure insertRelatedRbacObject();
$sql$, targetTable, targetTable);
execute createInsertTriggerSQL;
createDeleteTriggerSQL = format($sql$
create trigger deleteRbacRulesFor_%s_Trigger
before delete
on %s
for each row
execute procedure deleteRelatedRbacObject();
$sql$, targetTable, targetTable);
execute createDeleteTriggerSQL;
end; $$;
--//
-- ============================================================================
--changeset rbac-base-ROLE:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
@ -160,9 +213,9 @@ create type RbacRoleType as enum ('owner', 'admin', 'tenant');
create table RbacRole
(
uuid uuid primary key references RbacReference (uuid) on delete cascade,
objectUuid uuid references RbacObject (uuid) not null,
roleType RbacRoleType not null,
uuid uuid primary key references RbacReference (uuid) on delete cascade initially deferred, -- initially deferred
objectUuid uuid not null references RbacObject (uuid) initially deferred,
roleType RbacRoleType not null,
unique (objectUuid, roleType)
);
@ -269,13 +322,13 @@ $$;
-- ============================================================================
--changeset hs-admin-person-rbac-ROLES-REMOVAL:1 endDelimiter:--//
--changeset rbac-base-BEFORE-DELETE-ROLE-TRIGGER:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
RbacRole BEFORE DELETE TRIGGER function which deletes all related roles.
*/
create or replace function deleteRbacGrantsForRbacRole()
create or replace function deleteRbacGrantsOfRbacRole()
returns trigger
language plpgsql
strict as $$
@ -291,11 +344,43 @@ end; $$;
/*
Installs the RbacRole BEFORE DELETE TRIGGER.
*/
create trigger deleteRbacGrantsForRbacRole_Trigger
create trigger deleteRbacGrantsOfRbacRole_Trigger
before delete
on RbacRole
for each row
execute procedure deleteRbacGrantsForRbacRole();
execute procedure deleteRbacGrantsOfRbacRole();
--//
-- ============================================================================
--changeset rbac-base-BEFORE-DELETE-OBJECT-TRIGGER:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
RbacObject BEFORE DELETE TRIGGER function which deletes all related roles.
*/
create or replace function deleteRbacRolesOfRbacObject()
returns trigger
language plpgsql
strict as $$
begin
if TG_OP = 'DELETE' then
delete from RbacPermission p where p.objectuuid = old.uuid;
delete from RbacRole r where r.objectUuid = old.uuid;
else
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if;
return old;
end; $$;
/*
Installs the RbacRole BEFORE DELETE TRIGGER.
*/
create trigger deleteRbacRolesOfRbacObject_Trigger
before delete
on RbacObject
for each row
execute procedure deleteRbacRolesOfRbacObject();
--//

View File

@ -12,7 +12,7 @@ create trigger createRbacObjectForCustomer_Trigger
before insert
on test_customer
for each row
execute procedure createRbacObject();
execute procedure insertRelatedRbacObject();
--//
-- ============================================================================
@ -106,40 +106,6 @@ execute procedure createRbacRolesForTestCustomer();
--//
-- ============================================================================
--changeset test-customer-rbac-ROLES-REMOVAL:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Deletes the roles and their assignments of a deleted customer for the BEFORE DELETE TRIGGER.
*/
create or replace function deleteRbacRulesForTestCustomer()
returns trigger
language plpgsql
strict as $$
begin
if TG_OP = 'DELETE' then
call deleteRole(findRoleId(testCustomerOwner(OLD)));
call deleteRole(findRoleId(testCustomerAdmin(OLD)));
call deleteRole(findRoleId(testCustomerTenant(OLD)));
else
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if;
end; $$;
/*
An BEFORE DELETE TRIGGER which deletes the role structure of a customer.
*/
drop trigger if exists deleteRbacRulesForTestCustomer_Trigger on test_customer;
create trigger deleteRbacRulesForTestCustomer_Trigger
before delete
on test_customer
for each row
execute procedure deleteRbacRulesForTestCustomer();
--//
-- ============================================================================
--changeset test-customer-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------

View File

@ -11,7 +11,7 @@ create trigger createRbacObjectForPackage_Trigger
before insert
on test_package
for each row
execute procedure createRbacObject();
execute procedure insertRelatedRbacObject();
--//
@ -103,40 +103,6 @@ create trigger createRbacRolesForTestPackage_Trigger
execute procedure createRbacRolesForTestPackage();
--//
-- ============================================================================
--changeset test-package-rbac-ROLES-REMOVAL:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Deletes the roles and their assignments of a deleted package for the BEFORE DELETE TRIGGER.
*/
create or replace function deleteRbacRulesForTestPackage()
returns trigger
language plpgsql
strict as $$
begin
if TG_OP = 'DELETE' then
call deleteRole(findRoleId(testPackageOwner(OLD)));
call deleteRole(findRoleId(testPackageAdmin(OLD)));
call deleteRole(findRoleId(testPackageTenant(OLD)));
else
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if;
end; $$;
/*
An BEFORE DELETE TRIGGER which deletes the role structure of a package.
*/
drop trigger if exists deleteRbacRulesForTestPackage_Trigger on test_package;
create trigger deleteRbacRulesForTestPackage_Trigger
before delete
on test_package
for each row
execute procedure deleteRbacRulesForTestPackage();
--//
-- ============================================================================
--changeset test-package-rbac-IDENTITY-VIEW:1 endDelimiter:--//

View File

@ -11,7 +11,7 @@ create trigger createRbacObjectFortest_domain_Trigger
before insert
on test_domain
for each row
execute procedure createRbacObject();
execute procedure insertRelatedRbacObject();
--//
@ -121,41 +121,6 @@ execute procedure createRbacRulesForTestDomain();
--//
-- ============================================================================
--changeset test-domain-rbac-ROLES-REMOVAL:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Deletes the roles and their assignments of a deleted domain for the BEFORE DELETE TRIGGER.
*/
create or replace function deleteRbacRulesForTestDomain()
returns trigger
language plpgsql
strict as $$
begin
if TG_OP = 'DELETE' then
call deleteRole(findRoleId(testdomainOwner(OLD)));
call deleteRole(findRoleId(testdomainAdmin(OLD)));
call deleteRole(findRoleId(testdomainTenant(OLD)));
else
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if;
end; $$;
/*
An BEFORE DELETE TRIGGER which deletes the role structure of a domain.
*/
drop trigger if exists deleteRbacRulesForTestDomain_Trigger on test_package;
create trigger deleteRbacRulesForTestDomain_Trigger
before delete
on test_domain
for each row
execute procedure deleteRbacRulesForTestDomain();
--//
-- ============================================================================
--changeset test-domain-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------

View File

@ -6,7 +6,7 @@
create table if not exists hs_admin_contact
(
uuid uuid unique references RbacObject (uuid) on delete cascade,
uuid uuid unique references RbacObject (uuid) initially deferred,
label varchar(96) not null,
postalAddress text,
emailAddresses text, -- TODO.feat: change to json

View File

@ -1,19 +1,12 @@
--liquibase formatted sql
-- ============================================================================
--changeset hs-admin-contact-rbac-CREATE-OBJECT:1 endDelimiter:--//
--changeset hs-admin-contact-rbac-OBJECT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates the related RbacObject through a BEFORE INSERT TRIGGER.
*/
create trigger createRbacObjectForHsAdminCustomer_Trigger
before insert
on hs_admin_contact
for each row
execute procedure createRbacObject();
call generateRelatedRbacObject('hs_admin_contact');
--//
-- ============================================================================
--changeset hs-admin-contact-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
@ -103,37 +96,6 @@ execute procedure createRbacRolesForHsAdminContact();
--//
-- ============================================================================
--changeset hs-admin-contact-rbac-ROLES-REMOVAL:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Deletes the roles and their assignments of a deleted contact for the BEFORE DELETE TRIGGER.
*/
create or replace function deleteRbacRulesForHsAdminContact()
returns trigger
language plpgsql
strict as $$
begin
if TG_OP = 'DELETE' then
call deleteRole(findRoleId(hsAdminContactOwner(OLD)));
call deleteRole(findRoleId(hsAdminContactTenant(OLD)));
else
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if;
return old;
end; $$;
/*
An BEFORE DELETE TRIGGER which deletes the role structure of a contact.
*/
create trigger deleteRbacRulesForTestContact_Trigger
before delete
on hs_admin_contact
for each row
execute procedure deleteRbacRulesForHsAdminContact();
--//
-- ============================================================================
--changeset hs-admin-contact-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------

View File

@ -10,7 +10,7 @@ CREATE CAST (character varying as HsAdminPersonType) WITH INOUT AS IMPLICIT;
create table if not exists hs_admin_person
(
uuid uuid unique references RbacObject (uuid) on delete cascade,
uuid uuid unique references RbacObject (uuid) initially deferred,
personType HsAdminPersonType not null,
tradeName varchar(96),
givenName varchar(48),

View File

@ -1,19 +1,13 @@
--liquibase formatted sql
-- ============================================================================
--changeset hs-admin-person-rbac-CREATE-OBJECT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates the related RbacObject through a BEFORE INSERT TRIGGER.
*/
create trigger createRbacObjectForHsAdminPerson_Trigger
before insert
on hs_admin_person
for each row
execute procedure createRbacObject();
-- ============================================================================
--changeset hs-admin-person-rbac-OBJECT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
call generateRelatedRbacObject('hs_admin_person');
--//
-- ============================================================================
--changeset hs-admin-person-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
@ -103,40 +97,6 @@ execute procedure createRbacRolesForHsAdminPerson();
--//
-- ============================================================================
--changeset hs-admin-person-rbac-ROLES-REMOVAL:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
-- TODO: can we replace all these delete triggers by a delete trigger on RbacObject?
/*
Deletes the roles and their assignments of a deleted person for the BEFORE DELETE TRIGGER.
*/
create or replace function deleteRbacRulesForHsAdminPerson()
returns trigger
language plpgsql
strict as $$
begin
if TG_OP = 'DELETE' then
call deleteRole(findRoleId(hsAdminPersonOwner(OLD)));
call deleteRole(findRoleId(hsAdminPersonAdmin(OLD)));
call deleteRole(findRoleId(hsAdminPersonTenant(OLD)));
else
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if;
return old;
end; $$;
/*
An BEFORE DELETE TRIGGER which deletes the role structure of a person.
*/
create trigger deleteRbacRulesForTestPerson_Trigger
before delete
on hs_admin_person
for each row
execute procedure deleteRbacRulesForHsAdminPerson();
--//
-- ============================================================================
--changeset hs-admin-person-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------

View File

@ -6,7 +6,7 @@
create table if not exists hs_admin_partner
(
uuid uuid unique references RbacObject (uuid) on delete cascade,
uuid uuid unique references RbacObject (uuid) initially deferred, -- on delete cascade
personUuid uuid not null references hs_admin_person(uuid),
contactUuid uuid not null references hs_admin_contact(uuid),
registrationOffice varchar(96),

View File

@ -1,19 +1,12 @@
--liquibase formatted sql
-- ============================================================================
--changeset hs-admin-partner-rbac-CREATE-OBJECT:1 endDelimiter:--//
--changeset hs-admin-partner-rbac-OBJECT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates the related RbacObject through a BEFORE INSERT TRIGGER.
*/
create trigger createRbacObjectForHsAdminPartner_Trigger
before insert
on hs_admin_partner
for each row
execute procedure createRbacObject();
call generateRelatedRbacObject('hs_admin_partner');
--//
-- ============================================================================
--changeset hs-admin-partner-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
@ -106,38 +99,6 @@ execute procedure createRbacRolesForHsAdminPartner();
--//
-- ============================================================================
--changeset hs-admin-partner-rbac-ROLES-REMOVAL:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Deletes the roles and their assignments of a deleted partner for the BEFORE DELETE TRIGGER.
*/
create or replace function deleteRbacRulesForHsAdminPartner()
returns trigger
language plpgsql
strict as $$
begin
if TG_OP = 'DELETE' then
call deleteRole(findRoleId(hsAdminPartnerOwner(OLD)));
call deleteRole(findRoleId(hsAdminPartnerAdmin(OLD)));
call deleteRole(findRoleId(hsAdminPartnerTenant(OLD)));
else
raise exception 'invalid usage of TRIGGER BEFORE DELETE';
end if;
return old;
end; $$;
/*
An BEFORE DELETE TRIGGER which deletes the role structure of a partner.
*/
create trigger deleteRbacRulesForTestPartner_Trigger
before delete
on hs_admin_partner
for each row
execute procedure deleteRbacRulesForHsAdminPartner();
--//
-- ============================================================================
--changeset hs-admin-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ----------------------------------------------------------------------------

View File

@ -95,9 +95,9 @@ class HsAdminPartnerRepositoryIntegrationTest extends ContextBasedTest {
public void createsAndGrantsRoles() {
// given
context("alex@hostsharing.net");
final var initialRoleCount = rawRoleRepo.findAll().size();
final var initialRoleNames = roleNamesOf(rawRoleRepo.findAll());
final var initialGrantCount = rawGrantRepo.findAll().size();
final var initialGrantsDisplayNames = grantDisplaysOf(rawGrantRepo.findAll());
final var initialGrantsDisplayNames = grantDisplaysOf(rawGrantRepo.findAll()); // TODO
// when
attempt(em, () -> {
@ -112,12 +112,11 @@ class HsAdminPartnerRepositoryIntegrationTest extends ContextBasedTest {
});
// then
assertThat(roleNamesOf(rawRoleRepo.findAll())).containsAll(List.of(
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.admin",
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.owner",
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.tenant"))
.as("invalid number of roles created")
.hasSize(initialRoleCount + 3);
assertThat(roleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(Array.from(
initialRoleNames,
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.admin",
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.owner",
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.tenant"));
assertThat(grantDisplaysOf(rawGrantRepo.findAll())).containsAll(List.of(
"{ grant role hs_admin_partner#ErbenBesslerMelBessler-forthcontact.owner to role global#global.admin by system and assume }",
"{ grant role hs_admin_partner#ErbenBesslerMelBessler-forthcontact.tenant to role hs_admin_contact#forthcontact.admin by system and assume }",
@ -245,19 +244,29 @@ class HsAdminPartnerRepositoryIntegrationTest extends ContextBasedTest {
final var result = jpaAttempt.transacted(() -> {
context("alex@hostsharing.net");
partnerRepo.deleteByUuid(givenPartner.getUuid());
}).assertSuccessful();
});
// then
final var roles = rawRoleRepo.findAll();
assertThat(roleNamesOf(roles)).containsExactlyInAnyOrder(initialRoleNames);
result.assertSuccessful();
jpaAttempt.transacted(() -> {
final var remainingPartner = em.createNativeQuery("select p.uuid from hs_admin_partner p where p.uuid=?1")
.setParameter(1, givenPartner.getUuid()).getResultList();
assertThat(remainingPartner).isEmpty();
final var remainingObject = em.createNativeQuery("select o.uuid from RbacObject o where o.uuid=?1")
.setParameter(1, givenPartner.getUuid())
.getResultList();
assertThat(remainingObject).isEmpty();
context("customer-admin@forthcontact.example.com");
assertThat(grantDisplaysOf(rawGrantRepo.findAll())).doesNotContain(
"{ grant assumed role hs_admin_contact#forthcontact.owner to user customer-admin@forthcontact.example.com by role global#global.admin }");
assertThat(roleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(initialRoleNames);
context("person-ErbenBesslerMelBessler@example.com");
assertThat(grantDisplaysOf(rawGrantRepo.findAll())).doesNotContain(
"{ grant assumed role hs_admin_person#ErbenBesslerMelBessler.owner to user person-ErbenBesslerMelBessl@example.com by role global#global.admin }");
context("customer-admin@forthcontact.example.com");
assertThat(grantDisplaysOf(rawGrantRepo.findAll())).doesNotContain(
"{ grant assumed role hs_admin_contact#forthcontact.owner to user customer-admin@forthcontact.example.com by role global#global.admin }");
context("person-ErbenBesslerMelBessler@example.com");
assertThat(grantDisplaysOf(rawGrantRepo.findAll())).doesNotContain(
"{ grant assumed role hs_admin_person#ErbenBesslerMelBessler.owner to user person-ErbenBesslerMelBessl@example.com by role global#global.admin }");
}).assertSuccessful();
}
}

View File

@ -71,7 +71,6 @@ public class JpaAttempt {
});
return JpaResult.forVoidValue();
} catch (final RuntimeException exc) {
return new JpaResult<>(null, exc);
}
}