2022-08-16 10:46:41 +02:00
|
|
|
--liquibase formatted sql
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
|
|
--changeset rbac-user-grant-GRANT-ROLE-TO-USER:1 endDelimiter:--//
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
|
2024-09-13 14:53:40 +02:00
|
|
|
create or replace function rbac.assumedRoleUuid()
|
2022-08-16 10:46:41 +02:00
|
|
|
returns uuid
|
2024-01-23 15:11:23 +01:00
|
|
|
stable -- leakproof
|
2022-08-16 10:46:41 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
declare
|
2024-09-13 12:44:56 +02:00
|
|
|
currentSubjectOrAssumedRolesUuids uuid[];
|
2022-08-16 10:46:41 +02:00
|
|
|
begin
|
|
|
|
-- exactly one role must be assumed, not none not more than one
|
2024-09-13 20:21:12 +02:00
|
|
|
if cardinality(base.assumedRoles()) <> 1 then
|
|
|
|
raise exception '[400] Granting roles to user is only possible if exactly one role is assumed, given: %', base.assumedRoles();
|
2022-08-16 10:46:41 +02:00
|
|
|
end if;
|
|
|
|
|
2024-09-13 12:44:56 +02:00
|
|
|
currentSubjectOrAssumedRolesUuids := rbac.currentSubjectOrAssumedRolesUuids();
|
|
|
|
return currentSubjectOrAssumedRolesUuids[1];
|
2022-08-16 10:46:41 +02:00
|
|
|
end; $$;
|
|
|
|
|
2024-09-13 16:20:14 +02:00
|
|
|
create or replace procedure rbac.grantRoleToUserUnchecked(grantedByRoleUuid uuid, grantedRoleUuid uuid, subjectUuid uuid, doAssume boolean = true)
|
2022-08-16 10:46:41 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
begin
|
2024-09-13 20:46:54 +02:00
|
|
|
perform rbac.assertReferenceType('grantingRoleUuid', grantedByRoleUuid, 'rbac.role');
|
|
|
|
perform rbac.assertReferenceType('roleId (descendant)', grantedRoleUuid, 'rbac.role');
|
2024-09-13 16:20:14 +02:00
|
|
|
perform rbac.assertReferenceType('subjectUuid (ascendant)', subjectUuid, 'rbac.subject');
|
2022-08-16 10:46:41 +02:00
|
|
|
|
|
|
|
insert
|
2024-09-13 20:31:41 +02:00
|
|
|
into rbac.grants (grantedByRoleUuid, ascendantUuid, descendantUuid, assumed)
|
2024-09-13 16:20:14 +02:00
|
|
|
values (grantedByRoleUuid, subjectUuid, grantedRoleUuid, doAssume)
|
2024-04-08 11:16:06 +02:00
|
|
|
-- TODO: check if grantedByRoleUuid+doAssume are the same, otherwise raise exception?
|
|
|
|
on conflict do nothing; -- allow granting multiple times
|
2022-08-16 10:46:41 +02:00
|
|
|
end; $$;
|
|
|
|
|
2024-09-13 16:20:14 +02:00
|
|
|
create or replace procedure rbac.grantRoleToSubject(grantedByRoleUuid uuid, grantedRoleUuid uuid, subjectUuid uuid, doAssume boolean = true)
|
2022-08-16 10:46:41 +02:00
|
|
|
language plpgsql as $$
|
2024-03-11 12:30:43 +01:00
|
|
|
declare
|
|
|
|
grantedByRoleIdName text;
|
|
|
|
grantedRoleIdName text;
|
2022-08-16 10:46:41 +02:00
|
|
|
begin
|
2024-09-13 20:46:54 +02:00
|
|
|
perform rbac.assertReferenceType('grantingRoleUuid', grantedByRoleUuid, 'rbac.role');
|
|
|
|
perform rbac.assertReferenceType('grantedRoleUuid (descendant)', grantedRoleUuid, 'rbac.role');
|
2024-09-13 16:20:14 +02:00
|
|
|
perform rbac.assertReferenceType('subjectUuid (ascendant)', subjectUuid, 'rbac.subject');
|
2022-08-16 10:46:41 +02:00
|
|
|
|
2024-03-11 12:30:43 +01:00
|
|
|
assert grantedByRoleUuid is not null, 'grantedByRoleUuid must not be null';
|
|
|
|
assert grantedRoleUuid is not null, 'grantedRoleUuid must not be null';
|
2024-09-13 16:20:14 +02:00
|
|
|
assert subjectUuid is not null, 'subjectUuid must not be null';
|
2024-03-11 12:30:43 +01:00
|
|
|
|
2024-09-14 10:34:11 +02:00
|
|
|
if NOT rbac.isGranted(rbac.currentSubjectOrAssumedRolesUuids(), grantedByRoleUuid) then
|
2024-09-13 20:46:54 +02:00
|
|
|
select roleIdName from rbac.role_ev where uuid=grantedByRoleUuid into grantedByRoleIdName;
|
2024-03-11 12:30:43 +01:00
|
|
|
raise exception '[403] Access to granted-by-role % (%) forbidden for % (%)',
|
2024-09-14 10:58:57 +02:00
|
|
|
grantedByRoleIdName, grantedByRoleUuid, base.currentSubjects(), rbac.currentSubjectOrAssumedRolesUuids();
|
2022-08-16 10:46:41 +02:00
|
|
|
end if;
|
2024-09-14 10:34:11 +02:00
|
|
|
if NOT rbac.isGranted(grantedByRoleUuid, grantedRoleUuid) then
|
2024-09-13 20:46:54 +02:00
|
|
|
select roleIdName from rbac.role_ev where uuid=grantedByRoleUuid into grantedByRoleIdName;
|
|
|
|
select roleIdName from rbac.role_ev where uuid=grantedRoleUuid into grantedRoleIdName;
|
2024-03-11 12:30:43 +01:00
|
|
|
raise exception '[403] Access to granted role % (%) forbidden for % (%)',
|
|
|
|
grantedRoleIdName, grantedRoleUuid, grantedByRoleIdName, grantedByRoleUuid;
|
2022-08-16 10:46:41 +02:00
|
|
|
end if;
|
|
|
|
|
|
|
|
insert
|
2024-09-13 20:31:41 +02:00
|
|
|
into rbac.grants (grantedByRoleUuid, ascendantUuid, descendantUuid, assumed)
|
2024-09-13 16:20:14 +02:00
|
|
|
values (grantedByRoleUuid, subjectUuid, grantedRoleUuid, doAssume);
|
|
|
|
-- TODO.impl: What should happen on multiple grants? What if options (doAssume) are not the same?
|
2022-08-16 10:46:41 +02:00
|
|
|
-- Most powerful or latest grant wins? What about managed?
|
|
|
|
-- on conflict do nothing; -- allow granting multiple times
|
|
|
|
end; $$;
|
|
|
|
--//
|
|
|
|
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
|
|
--changeset rbac-user-grant-REVOKE-ROLE-FROM-USER:1 endDelimiter:--//
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
|
2024-09-13 16:20:14 +02:00
|
|
|
create or replace procedure rbac.checkRevokeRoleFromSubjectPreconditions(grantedByRoleUuid uuid, grantedRoleUuid uuid, subjectUuid uuid)
|
2022-08-16 10:46:41 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
begin
|
2024-09-13 20:46:54 +02:00
|
|
|
perform rbac.assertReferenceType('grantedByRoleUuid', grantedByRoleUuid, 'rbac.role');
|
|
|
|
perform rbac.assertReferenceType('grantedRoleUuid (descendant)', grantedRoleUuid, 'rbac.role');
|
2024-09-13 16:20:14 +02:00
|
|
|
perform rbac.assertReferenceType('subjectUuid (ascendant)', subjectUuid, 'rbac.subject');
|
2022-08-16 10:46:41 +02:00
|
|
|
|
2024-09-14 10:34:11 +02:00
|
|
|
if NOT rbac.isGranted(rbac.currentSubjectOrAssumedRolesUuids(), grantedByRoleUuid) then
|
2024-09-14 10:58:57 +02:00
|
|
|
raise exception '[403] Revoking role created by % is forbidden for %.', grantedByRoleUuid, base.currentSubjects();
|
2022-08-16 10:46:41 +02:00
|
|
|
end if;
|
|
|
|
|
2024-09-14 10:34:11 +02:00
|
|
|
if NOT rbac.isGranted(grantedByRoleUuid, grantedRoleUuid) then
|
2024-09-14 10:58:57 +02:00
|
|
|
raise exception '[403] Revoking role % is forbidden for %.', grantedRoleUuid, base.currentSubjects();
|
2022-08-16 10:46:41 +02:00
|
|
|
end if;
|
|
|
|
|
2024-09-14 10:34:11 +02:00
|
|
|
--raise exception 'rbac.isGranted(%, %)', rbac.currentSubjectOrAssumedRolesUuids(), grantedByRoleUuid;
|
|
|
|
if NOT rbac.isGranted(rbac.currentSubjectOrAssumedRolesUuids(), grantedByRoleUuid) then
|
2024-09-14 10:58:57 +02:00
|
|
|
raise exception '[403] Revoking role granted by % is forbidden for %.', grantedByRoleUuid, base.currentSubjects();
|
2022-08-16 10:46:41 +02:00
|
|
|
end if;
|
|
|
|
|
2024-09-14 10:34:11 +02:00
|
|
|
if NOT rbac.isGranted(subjectUuid, grantedRoleUuid) then
|
2024-09-13 16:20:14 +02:00
|
|
|
raise exception '[404] No such grant found granted by % for subject % to role %.', grantedByRoleUuid, subjectUuid, grantedRoleUuid;
|
2022-08-16 10:46:41 +02:00
|
|
|
end if;
|
|
|
|
end; $$;
|
|
|
|
|
2024-09-13 16:20:14 +02:00
|
|
|
create or replace procedure rbac.revokeRoleFromSubject(grantedByRoleUuid uuid, grantedRoleUuid uuid, subjectUuid uuid)
|
2022-08-16 10:46:41 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
begin
|
2024-09-13 16:20:14 +02:00
|
|
|
call rbac.checkRevokeRoleFromSubjectPreconditions(grantedByRoleUuid, grantedRoleUuid, subjectUuid);
|
2022-08-16 10:46:41 +02:00
|
|
|
|
2024-09-13 20:31:41 +02:00
|
|
|
raise INFO 'delete from rbac.grants where ascendantUuid = % and descendantUuid = %', subjectUuid, grantedRoleUuid;
|
|
|
|
delete from rbac.grants as g
|
2024-09-13 16:20:14 +02:00
|
|
|
where g.ascendantUuid = subjectUuid and g.descendantUuid = grantedRoleUuid
|
|
|
|
and g.grantedByRoleUuid = revokeRoleFromSubject.grantedByRoleUuid;
|
2022-08-16 10:46:41 +02:00
|
|
|
end; $$;
|
2024-03-11 12:30:43 +01:00
|
|
|
--//
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
|
|
--changeset rbac-user-grant-REVOKE-PERMISSION-FROM-ROLE:1 endDelimiter:--//
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
|
2024-09-13 16:20:14 +02:00
|
|
|
create or replace procedure rbac.revokePermissionFromRole(permissionUuid uuid, superRoleUuid uuid)
|
2024-03-11 12:30:43 +01:00
|
|
|
language plpgsql as $$
|
|
|
|
begin
|
2024-09-13 20:31:41 +02:00
|
|
|
raise INFO 'delete from rbac.grants where ascendantUuid = % and descendantUuid = %', superRoleUuid, permissionUuid;
|
|
|
|
delete from rbac.grants as g
|
2024-03-11 12:30:43 +01:00
|
|
|
where g.ascendantUuid = superRoleUuid and g.descendantUuid = permissionUuid;
|
|
|
|
end; $$;
|
|
|
|
--//
|