180 lines
7.2 KiB
MySQL
Raw Normal View History

--liquibase formatted sql
-- ============================================================================
--changeset michael.hoennig:rbac-context-DETERMINE endDelimiter:--//
-- ----------------------------------------------------------------------------
create or replace function rbac.determineCurrentSubjectUuid(currentSubject varchar)
returns uuid
stable -- leakproof
language plpgsql as $$
declare
currentSubjectUuid uuid;
begin
if currentSubject = '' then
return null;
end if;
select uuid from rbac.subject where name = currentSubject into currentSubjectUuid;
if currentSubjectUuid is null then
raise exception '[401] subject % given in `base.defineContext(...)` does not exist', currentSubject;
end if;
return currentSubjectUuid;
end; $$;
create or replace function rbac.determinecurrentsubjectorassumedrolesuuids(currentSubjectOrAssumedRolesUuids uuid, assumedRoles varchar)
returns uuid[]
stable -- leakproof
language plpgsql as $$
declare
roleName text;
roleNameParts text;
objectTableToAssume varchar(63);
objectNameToAssume varchar(63);
objectUuidToAssume uuid;
roleTypeToAssume rbac.RoleType;
roleIdsToAssume uuid[];
roleUuidToAssume uuid;
begin
if currentSubjectOrAssumedRolesUuids is null then
if length(coalesce(assumedRoles, '')) > 0 then
raise exception '[403] undefined has no permission to assume role %', assumedRoles;
else
return array[]::uuid[];
end if;
end if;
if length(coalesce(assumedRoles, '')) = 0 then
return array [currentSubjectOrAssumedRolesUuids];
end if;
foreach roleName in array string_to_array(assumedRoles, ';')
loop
roleNameParts = overlay(roleName placing '#' from length(roleName) + 1 - strpos(reverse(roleName), ':'));
objectTableToAssume = split_part(roleNameParts, '#', 1);
objectNameToAssume = split_part(roleNameParts, '#', 2);
roleTypeToAssume = split_part(roleNameParts, '#', 3);
objectUuidToAssume = rbac.findObjectUuidByIdName(objectTableToAssume, objectNameToAssume);
if objectUuidToAssume is null then
raise exception '[401] object % cannot be found in table % (from roleNameParts=%)', objectNameToAssume, objectTableToAssume, roleNameParts;
end if;
select uuid
from rbac.role r
where r.objectUuid = objectUuidToAssume
and r.roleType = roleTypeToAssume
into roleUuidToAssume;
if roleUuidToAssume is null then
raise exception '[403] role % does not exist or is not accessible for subject %', roleName, base.currentSubject();
end if;
if not rbac.isGranted(currentSubjectOrAssumedRolesUuids, roleUuidToAssume) then
raise exception '[403] subject % has no permission to assume role %', base.currentSubject(), roleName;
end if;
roleIdsToAssume := roleIdsToAssume || roleUuidToAssume;
end loop;
return roleIdsToAssume;
end; $$;
-- ============================================================================
--changeset michael.hoennig:rbac-context-CONTEXT-DEFINED endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Callback which is called after the context has been (re-) defined.
This function will be overwritten by later changesets.
*/
create or replace procedure base.contextDefined(
currentTask varchar(127),
currentRequest text,
currentSubject varchar(63),
assumedRoles varchar(1023)
)
language plpgsql as $$
declare
currentSubjectUuid uuid;
begin
execute format('set local hsadminng.currentTask to %L', currentTask);
execute format('set local hsadminng.currentRequest to %L', currentRequest);
execute format('set local hsadminng.currentSubject to %L', currentSubject);
select rbac.determineCurrentSubjectUuid(currentSubject) into currentSubjectUuid;
execute format('set local hsadminng.currentSubjectUuid to %L', coalesce(currentSubjectUuid::text, ''));
execute format('set local hsadminng.assumedRoles to %L', assumedRoles);
execute format('set local hsadminng.currentSubjectOrAssumedRolesUuids to %L',
(select array_to_string(rbac.determinecurrentsubjectorassumedrolesuuids(currentSubjectUuid, assumedRoles), ';')));
raise notice 'Context defined as: %, %, %, [%]', currentTask, currentRequest, currentSubject, assumedRoles;
end; $$;
-- ============================================================================
--changeset michael.hoennig:rbac-context-current-subject-ID endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Returns the uuid of the current subject as set via `base.defineContext(...)`.
*/
create or replace function rbac.currentSubjectUuid()
returns uuid
stable -- leakproof
language plpgsql as $$
declare
currentSubjectUuid text;
currentSubjectName text;
begin
begin
currentSubjectUuid := current_setting('hsadminng.currentSubjectUuid');
exception
when others then
currentSubjectUuid := null;
end;
if (currentSubjectUuid is null or currentSubjectUuid = '') then
currentSubjectName := base.currentSubject();
if (length(currentSubjectName) > 0) then
raise exception '[401] currentSubjectUuid cannot be determined, unknown subject name "%"', currentSubjectName;
else
raise exception '[401] currentSubjectUuid cannot be determined, please call `base.defineContext(...)` first;"';
end if;
end if;
return currentSubjectUuid::uuid;
end; $$;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-context-CURRENT-SUBJECT-UUIDS endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Returns the uuid of the current subject as set via `base.defineContext(...)`,
or, if any, the uuids of all assumed roles as set via `base.defineContext(...)`
or empty array, if context is not defined.
*/
create or replace function rbac.currentSubjectOrAssumedRolesUuids()
returns uuid[]
stable -- leakproof
language plpgsql as $$
declare
currentSubjectOrAssumedRolesUuids text;
currentSubjectName text;
begin
begin
currentSubjectOrAssumedRolesUuids := current_setting('hsadminng.currentSubjectOrAssumedRolesUuids');
exception
when others then
currentSubjectOrAssumedRolesUuids := null;
end;
if (currentSubjectOrAssumedRolesUuids is null or length(currentSubjectOrAssumedRolesUuids) = 0 ) then
currentSubjectName := base.currentSubject();
if (length(currentSubjectName) > 0) then
raise exception '[401] currentSubjectOrAssumedRolesUuids (%) cannot be determined, unknown subject name "%"', currentSubjectOrAssumedRolesUuids, currentSubjectName;
else
raise exception '[401] currentSubjectOrAssumedRolesUuids cannot be determined, please call `base.defineContext(...)` with a valid subject;"';
end if;
end if;
return string_to_array(currentSubjectOrAssumedRolesUuids, ';');
end; $$;
--//