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'); 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 returns trigger
language plpgsql language plpgsql
strict as $$ strict as $$
@ -147,8 +157,51 @@ begin
raise exception 'invalid usage of TRIGGER AFTER INSERT'; raise exception 'invalid usage of TRIGGER AFTER INSERT';
end if; end if;
end; $$; 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:--// --changeset rbac-base-ROLE:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
@ -160,9 +213,9 @@ create type RbacRoleType as enum ('owner', 'admin', 'tenant');
create table RbacRole create table RbacRole
( (
uuid uuid primary key references RbacReference (uuid) on delete cascade, uuid uuid primary key references RbacReference (uuid) on delete cascade initially deferred, -- initially deferred
objectUuid uuid references RbacObject (uuid) not null, objectUuid uuid not null references RbacObject (uuid) initially deferred,
roleType RbacRoleType not null, roleType RbacRoleType not null,
unique (objectUuid, roleType) 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. RbacRole BEFORE DELETE TRIGGER function which deletes all related roles.
*/ */
create or replace function deleteRbacGrantsForRbacRole() create or replace function deleteRbacGrantsOfRbacRole()
returns trigger returns trigger
language plpgsql language plpgsql
strict as $$ strict as $$
@ -291,11 +344,43 @@ end; $$;
/* /*
Installs the RbacRole BEFORE DELETE TRIGGER. Installs the RbacRole BEFORE DELETE TRIGGER.
*/ */
create trigger deleteRbacGrantsForRbacRole_Trigger create trigger deleteRbacGrantsOfRbacRole_Trigger
before delete before delete
on RbacRole on RbacRole
for each row 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 before insert
on test_customer on test_customer
for each row 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:--// --changeset test-customer-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------

View File

@ -11,7 +11,7 @@ create trigger createRbacObjectForPackage_Trigger
before insert before insert
on test_package on test_package
for each row for each row
execute procedure createRbacObject(); execute procedure insertRelatedRbacObject();
--// --//
@ -103,40 +103,6 @@ create trigger createRbacRolesForTestPackage_Trigger
execute procedure createRbacRolesForTestPackage(); 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:--// --changeset test-package-rbac-IDENTITY-VIEW:1 endDelimiter:--//

View File

@ -11,7 +11,7 @@ create trigger createRbacObjectFortest_domain_Trigger
before insert before insert
on test_domain on test_domain
for each row 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:--// --changeset test-domain-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------

View File

@ -6,7 +6,7 @@
create table if not exists hs_admin_contact 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, label varchar(96) not null,
postalAddress text, postalAddress text,
emailAddresses text, -- TODO.feat: change to json emailAddresses text, -- TODO.feat: change to json

View File

@ -1,19 +1,12 @@
--liquibase formatted sql --liquibase formatted sql
-- ============================================================================ -- ============================================================================
--changeset hs-admin-contact-rbac-CREATE-OBJECT:1 endDelimiter:--// --changeset hs-admin-contact-rbac-OBJECT:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRelatedRbacObject('hs_admin_contact');
/*
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();
--// --//
-- ============================================================================ -- ============================================================================
--changeset hs-admin-contact-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// --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:--// --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 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, personType HsAdminPersonType not null,
tradeName varchar(96), tradeName varchar(96),
givenName varchar(48), givenName varchar(48),

View File

@ -1,19 +1,13 @@
--liquibase formatted sql --liquibase formatted sql
-- ============================================================================
--changeset hs-admin-person-rbac-CREATE-OBJECT:1 endDelimiter:--//
-- ----------------------------------------------------------------------------
/* -- ============================================================================
Creates the related RbacObject through a BEFORE INSERT TRIGGER. --changeset hs-admin-person-rbac-OBJECT:1 endDelimiter:--//
*/ -- ----------------------------------------------------------------------------
create trigger createRbacObjectForHsAdminPerson_Trigger call generateRelatedRbacObject('hs_admin_person');
before insert
on hs_admin_person
for each row
execute procedure createRbacObject();
--// --//
-- ============================================================================ -- ============================================================================
--changeset hs-admin-person-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// --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:--// --changeset hs-admin-person-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------

View File

@ -6,7 +6,7 @@
create table if not exists hs_admin_partner 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), personUuid uuid not null references hs_admin_person(uuid),
contactUuid uuid not null references hs_admin_contact(uuid), contactUuid uuid not null references hs_admin_contact(uuid),
registrationOffice varchar(96), registrationOffice varchar(96),

View File

@ -1,19 +1,12 @@
--liquibase formatted sql --liquibase formatted sql
-- ============================================================================ -- ============================================================================
--changeset hs-admin-partner-rbac-CREATE-OBJECT:1 endDelimiter:--// --changeset hs-admin-partner-rbac-OBJECT:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------
call generateRelatedRbacObject('hs_admin_partner');
/*
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();
--// --//
-- ============================================================================ -- ============================================================================
--changeset hs-admin-partner-rbac-ROLE-DESCRIPTORS:1 endDelimiter:--// --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:--// --changeset hs-admin-partner-rbac-IDENTITY-VIEW:1 endDelimiter:--//
-- ---------------------------------------------------------------------------- -- ----------------------------------------------------------------------------

View File

@ -95,9 +95,9 @@ class HsAdminPartnerRepositoryIntegrationTest extends ContextBasedTest {
public void createsAndGrantsRoles() { public void createsAndGrantsRoles() {
// given // given
context("alex@hostsharing.net"); context("alex@hostsharing.net");
final var initialRoleCount = rawRoleRepo.findAll().size(); final var initialRoleNames = roleNamesOf(rawRoleRepo.findAll());
final var initialGrantCount = rawGrantRepo.findAll().size(); final var initialGrantCount = rawGrantRepo.findAll().size();
final var initialGrantsDisplayNames = grantDisplaysOf(rawGrantRepo.findAll()); final var initialGrantsDisplayNames = grantDisplaysOf(rawGrantRepo.findAll()); // TODO
// when // when
attempt(em, () -> { attempt(em, () -> {
@ -112,12 +112,11 @@ class HsAdminPartnerRepositoryIntegrationTest extends ContextBasedTest {
}); });
// then // then
assertThat(roleNamesOf(rawRoleRepo.findAll())).containsAll(List.of( assertThat(roleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(Array.from(
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.admin", initialRoleNames,
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.owner", "hs_admin_partner#ErbenBesslerMelBessler-forthcontact.admin",
"hs_admin_partner#ErbenBesslerMelBessler-forthcontact.tenant")) "hs_admin_partner#ErbenBesslerMelBessler-forthcontact.owner",
.as("invalid number of roles created") "hs_admin_partner#ErbenBesslerMelBessler-forthcontact.tenant"));
.hasSize(initialRoleCount + 3);
assertThat(grantDisplaysOf(rawGrantRepo.findAll())).containsAll(List.of( 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.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 }", "{ 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(() -> { final var result = jpaAttempt.transacted(() -> {
context("alex@hostsharing.net"); context("alex@hostsharing.net");
partnerRepo.deleteByUuid(givenPartner.getUuid()); partnerRepo.deleteByUuid(givenPartner.getUuid());
}).assertSuccessful(); });
// then // then
final var roles = rawRoleRepo.findAll(); result.assertSuccessful();
assertThat(roleNamesOf(roles)).containsExactlyInAnyOrder(initialRoleNames); 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(roleNamesOf(rawRoleRepo.findAll())).containsExactlyInAnyOrder(initialRoleNames);
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"); context("customer-admin@forthcontact.example.com");
assertThat(grantDisplaysOf(rawGrantRepo.findAll())).doesNotContain( assertThat(grantDisplaysOf(rawGrantRepo.findAll())).doesNotContain(
"{ grant assumed role hs_admin_person#ErbenBesslerMelBessler.owner to user person-ErbenBesslerMelBessl@example.com by role global#global.admin }"); "{ 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(); return JpaResult.forVoidValue();
} catch (final RuntimeException exc) { } catch (final RuntimeException exc) {
return new JpaResult<>(null, exc); return new JpaResult<>(null, exc);
} }
} }