188 lines
5.8 KiB
MySQL
188 lines
5.8 KiB
MySQL
|
--liquibase formatted sql
|
||
|
|
||
|
-- ============================================================================
|
||
|
--changeset rbac-current-CURRENT-USER:1 endDelimiter:--//
|
||
|
-- ----------------------------------------------------------------------------
|
||
|
/*
|
||
|
Returns the current user as set by `hsadminng.currentUser`.
|
||
|
Raises exception if not set.
|
||
|
*/
|
||
|
create or replace function currentUser()
|
||
|
returns varchar(63)
|
||
|
stable leakproof
|
||
|
language plpgsql as $$
|
||
|
declare
|
||
|
currentUser varchar(63);
|
||
|
begin
|
||
|
begin
|
||
|
currentUser := current_setting('hsadminng.currentUser');
|
||
|
exception
|
||
|
when others then
|
||
|
currentUser := null;
|
||
|
end;
|
||
|
if (currentUser is null or currentUser = '') then
|
||
|
raise exception 'hsadminng.currentUser must be defined, please use "SET LOCAL ...;"';
|
||
|
end if;
|
||
|
return currentUser;
|
||
|
end; $$;
|
||
|
|
||
|
create or replace function currentUserId()
|
||
|
returns uuid
|
||
|
stable leakproof
|
||
|
language plpgsql as $$
|
||
|
declare
|
||
|
currentUser varchar(63);
|
||
|
currentUserId uuid;
|
||
|
begin
|
||
|
currentUser := currentUser();
|
||
|
currentUserId = (select uuid from RbacUser where name = currentUser);
|
||
|
if currentUserId is null then
|
||
|
raise exception 'hsadminng.currentUser defined as %, but does not exists', currentUser;
|
||
|
end if;
|
||
|
return currentUserId;
|
||
|
end; $$;
|
||
|
--//
|
||
|
|
||
|
-- ============================================================================
|
||
|
--changeset rbac-current-ASSUMED-ROLES:1 endDelimiter:--//
|
||
|
-- ----------------------------------------------------------------------------
|
||
|
/*
|
||
|
Returns assumed role names as set in `hsadminng.assumedRoles`
|
||
|
or empty array, if not set.
|
||
|
*/
|
||
|
create or replace function assumedRoles()
|
||
|
returns varchar(63)[]
|
||
|
stable leakproof
|
||
|
language plpgsql as $$
|
||
|
declare
|
||
|
currentSubject varchar(63);
|
||
|
begin
|
||
|
begin
|
||
|
currentSubject := current_setting('hsadminng.assumedRoles');
|
||
|
exception
|
||
|
when others then
|
||
|
return array []::varchar[];
|
||
|
end;
|
||
|
if (currentSubject = '') then
|
||
|
return array []::varchar[];
|
||
|
end if;
|
||
|
return string_to_array(currentSubject, ';');
|
||
|
end; $$;
|
||
|
|
||
|
create or replace function pureIdentifier(rawIdentifier varchar)
|
||
|
returns varchar
|
||
|
returns null on null input
|
||
|
language plpgsql as $$
|
||
|
begin
|
||
|
return regexp_replace(rawIdentifier, '\W+', '');
|
||
|
end; $$;
|
||
|
|
||
|
create or replace function findObjectUuidByIdName(objectTable varchar, objectIdName varchar)
|
||
|
returns uuid
|
||
|
returns null on null input
|
||
|
language plpgsql as $$
|
||
|
declare
|
||
|
sql varchar;
|
||
|
uuid uuid;
|
||
|
begin
|
||
|
objectTable := pureIdentifier(objectTable);
|
||
|
objectIdName := pureIdentifier(objectIdName);
|
||
|
sql := format('select * from %sUuidByIdName(%L);', objectTable, objectIdName);
|
||
|
begin
|
||
|
raise notice 'sql: %', sql;
|
||
|
execute sql into uuid;
|
||
|
exception
|
||
|
when others then
|
||
|
raise exception 'function %UuidByIdName(...) not found, add identity view support for table %', objectTable, objectTable;
|
||
|
end;
|
||
|
return uuid;
|
||
|
end ; $$;
|
||
|
|
||
|
create or replace function findIdNameByObjectUuid(objectTable varchar, objectUuid uuid)
|
||
|
returns varchar
|
||
|
returns null on null input
|
||
|
language plpgsql as $$
|
||
|
declare
|
||
|
sql varchar;
|
||
|
idName varchar;
|
||
|
begin
|
||
|
objectTable := pureIdentifier(objectTable);
|
||
|
sql := format('select * from %sIdNameByUuid(%L::uuid);', objectTable, objectUuid);
|
||
|
begin
|
||
|
raise notice 'sql: %', sql;
|
||
|
execute sql into idName;
|
||
|
exception
|
||
|
when others then
|
||
|
raise exception 'function %IdNameByUuid(...) not found, add identity view support for table %', objectTable, objectTable;
|
||
|
end;
|
||
|
return idName;
|
||
|
end ; $$;
|
||
|
|
||
|
create or replace function currentSubjects()
|
||
|
returns varchar(63)[]
|
||
|
stable leakproof
|
||
|
language plpgsql as $$
|
||
|
declare
|
||
|
assumedRoles varchar(63)[];
|
||
|
begin
|
||
|
assumedRoles := assumedRoles();
|
||
|
if array_length(assumedRoles(), 1) > 0 then
|
||
|
return assumedRoles();
|
||
|
else
|
||
|
return array [currentUser()]::varchar(63)[];
|
||
|
end if;
|
||
|
end; $$;
|
||
|
|
||
|
create or replace function currentSubjectIds()
|
||
|
returns uuid[]
|
||
|
stable leakproof
|
||
|
language plpgsql as $$
|
||
|
declare
|
||
|
currentUserId uuid;
|
||
|
roleNames varchar(63)[];
|
||
|
roleName varchar(63);
|
||
|
objectTableToAssume varchar(63);
|
||
|
objectNameToAssume varchar(63);
|
||
|
objectUuidToAssume uuid;
|
||
|
roleTypeToAssume RbacRoleType;
|
||
|
roleIdsToAssume uuid[];
|
||
|
roleUuidToAssume uuid;
|
||
|
begin
|
||
|
currentUserId := currentUserId();
|
||
|
if currentUserId is null then
|
||
|
raise exception 'user % does not exist', currentUser();
|
||
|
end if;
|
||
|
|
||
|
roleNames := assumedRoles();
|
||
|
if cardinality(roleNames) = 0 then
|
||
|
return array [currentUserId];
|
||
|
end if;
|
||
|
|
||
|
raise notice 'assuming roles: %', roleNames;
|
||
|
|
||
|
foreach roleName in array roleNames
|
||
|
loop
|
||
|
roleName = overlay(roleName placing '#' from length(roleName) + 1 - strpos(reverse(roleName), '.'));
|
||
|
objectTableToAssume = split_part(roleName, '#', 1);
|
||
|
objectNameToAssume = split_part(roleName, '#', 2);
|
||
|
roleTypeToAssume = split_part(roleName, '#', 3);
|
||
|
|
||
|
objectUuidToAssume = findObjectUuidByIdName(objectTableToAssume, objectNameToAssume);
|
||
|
|
||
|
-- TODO: either the result needs to be cached at least per transaction or we need to get rid of SELCT in a loop
|
||
|
select uuid as roleuuidToAssume
|
||
|
from RbacRole r
|
||
|
where r.objectUuid = objectUuidToAssume
|
||
|
and r.roleType = roleTypeToAssume
|
||
|
into roleUuidToAssume;
|
||
|
if (not isGranted(currentUserId, roleUuidToAssume)) then
|
||
|
raise exception 'user % (%) has no permission to assume role % (%)', currentUser(), currentUserId, roleName, roleUuidToAssume;
|
||
|
end if;
|
||
|
roleIdsToAssume := roleIdsToAssume || roleUuidToAssume;
|
||
|
end loop;
|
||
|
|
||
|
return roleIdsToAssume;
|
||
|
end; $$;
|
||
|
--//
|
||
|
|