2022-08-04 17:19:45 +02:00
|
|
|
--liquibase formatted sql
|
|
|
|
|
2022-08-28 17:30:27 +02:00
|
|
|
|
|
|
|
-- ============================================================================
|
2024-09-16 15:36:37 +02:00
|
|
|
--changeset michael.hoennig:context-DEFINE endDelimiter:--//
|
2022-08-28 17:30:27 +02:00
|
|
|
-- ----------------------------------------------------------------------------
|
2022-08-30 09:35:59 +02:00
|
|
|
|
2022-08-28 17:30:27 +02:00
|
|
|
/*
|
2022-08-30 09:35:59 +02:00
|
|
|
Callback which is called after the context has been (re-) defined.
|
|
|
|
This function will be overwritten by later changesets.
|
2022-08-28 17:30:27 +02:00
|
|
|
*/
|
2024-09-16 15:36:37 +02:00
|
|
|
create procedure base.contextDefined(
|
2024-04-02 13:14:46 +02:00
|
|
|
currentTask varchar(127),
|
|
|
|
currentRequest text,
|
2024-09-16 15:36:37 +02:00
|
|
|
currentSubject varchar(63),
|
2024-04-02 13:14:46 +02:00
|
|
|
assumedRoles varchar(1023)
|
2022-08-30 09:35:59 +02:00
|
|
|
)
|
|
|
|
language plpgsql as $$
|
|
|
|
begin
|
|
|
|
end; $$;
|
2022-08-28 17:30:27 +02:00
|
|
|
|
2022-08-30 09:35:59 +02:00
|
|
|
/*
|
|
|
|
Defines the transaction context.
|
|
|
|
*/
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace procedure base.defineContext(
|
2024-04-02 11:04:56 +02:00
|
|
|
currentTask varchar(127),
|
2024-03-11 12:30:43 +01:00
|
|
|
currentRequest text = null,
|
2024-09-16 15:36:37 +02:00
|
|
|
currentSubject varchar(63) = null,
|
2024-03-28 12:15:13 +01:00
|
|
|
assumedRoles varchar(1023) = null
|
2022-08-28 17:30:27 +02:00
|
|
|
)
|
|
|
|
language plpgsql as $$
|
|
|
|
begin
|
2024-03-11 12:30:43 +01:00
|
|
|
currentTask := coalesce(currentTask, '');
|
2024-04-02 11:04:56 +02:00
|
|
|
assert length(currentTask) <= 127, FORMAT('currentTask must not be longer than 127 characters: "%s"', currentTask);
|
|
|
|
assert length(currentTask) >= 12, FORMAT('currentTask must be at least 12 characters long: "%s""', currentTask);
|
2022-08-28 17:30:27 +02:00
|
|
|
execute format('set local hsadminng.currentTask to %L', currentTask);
|
2022-08-30 09:35:59 +02:00
|
|
|
|
|
|
|
currentRequest := coalesce(currentRequest, '');
|
|
|
|
execute format('set local hsadminng.currentRequest to %L', currentRequest);
|
|
|
|
|
2024-09-16 15:36:37 +02:00
|
|
|
currentSubject := coalesce(currentSubject, '');
|
|
|
|
assert length(currentSubject) <= 63, FORMAT('currentSubject must not be longer than 63 characters: "%s"', currentSubject);
|
|
|
|
execute format('set local hsadminng.currentSubject to %L', currentSubject);
|
2022-08-30 09:35:59 +02:00
|
|
|
|
|
|
|
assumedRoles := coalesce(assumedRoles, '');
|
2024-03-28 12:15:13 +01:00
|
|
|
assert length(assumedRoles) <= 1023, FORMAT('assumedRoles must not be longer than 1023 characters: "%s"', assumedRoles);
|
2022-08-30 09:35:59 +02:00
|
|
|
execute format('set local hsadminng.assumedRoles to %L', assumedRoles);
|
|
|
|
|
2024-09-16 15:36:37 +02:00
|
|
|
call base.contextDefined(currentTask, currentRequest, currentSubject, assumedRoles);
|
2022-08-28 17:30:27 +02:00
|
|
|
end; $$;
|
|
|
|
--//
|
|
|
|
|
|
|
|
|
2022-08-04 17:19:45 +02:00
|
|
|
-- ============================================================================
|
2024-09-16 15:36:37 +02:00
|
|
|
--changeset michael.hoennig:context-CURRENT-TASK endDelimiter:--//
|
2022-08-23 14:36:22 +02:00
|
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
/*
|
2022-08-28 17:30:27 +02:00
|
|
|
Returns the current task as set by `hsadminng.currentTask`.
|
2022-08-23 14:36:22 +02:00
|
|
|
Raises exception if not set.
|
|
|
|
*/
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.currentTask()
|
2024-04-02 11:04:56 +02:00
|
|
|
returns varchar(127)
|
2024-01-23 15:11:23 +01:00
|
|
|
stable -- leakproof
|
2022-08-23 14:36:22 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
declare
|
2024-04-02 11:04:56 +02:00
|
|
|
currentTask varchar(127);
|
2022-08-23 14:36:22 +02:00
|
|
|
begin
|
|
|
|
begin
|
|
|
|
currentTask := current_setting('hsadminng.currentTask');
|
|
|
|
exception
|
|
|
|
when others then
|
|
|
|
currentTask := null;
|
|
|
|
end;
|
|
|
|
if (currentTask is null or currentTask = '') then
|
2024-09-16 15:36:37 +02:00
|
|
|
raise exception '[401] currentTask must be defined, please call `base.defineContext(...)`';
|
2022-08-23 14:36:22 +02:00
|
|
|
end if;
|
|
|
|
return currentTask;
|
|
|
|
end; $$;
|
|
|
|
--//
|
|
|
|
|
|
|
|
|
2022-08-30 13:38:12 +02:00
|
|
|
-- ============================================================================
|
2024-09-16 15:36:37 +02:00
|
|
|
--changeset michael.hoennig:context-CURRENT-REQUEST endDelimiter:--//
|
2022-08-30 13:38:12 +02:00
|
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
/*
|
2024-09-16 15:36:37 +02:00
|
|
|
Returns the current http request as set via `base.defineContext(...)`.
|
2022-08-30 13:38:12 +02:00
|
|
|
Raises exception if not set.
|
|
|
|
*/
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.currentRequest()
|
2024-03-28 12:15:13 +01:00
|
|
|
returns text
|
2024-01-23 15:11:23 +01:00
|
|
|
stable -- leakproof
|
2022-08-30 13:38:12 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
declare
|
2024-03-28 12:15:13 +01:00
|
|
|
currentRequest text;
|
2022-08-30 13:38:12 +02:00
|
|
|
begin
|
|
|
|
begin
|
|
|
|
currentRequest := current_setting('hsadminng.currentRequest');
|
|
|
|
exception
|
|
|
|
when others then
|
|
|
|
currentRequest := null;
|
|
|
|
end;
|
|
|
|
return currentRequest;
|
|
|
|
end; $$;
|
|
|
|
--//
|
|
|
|
|
|
|
|
|
2022-08-23 14:36:22 +02:00
|
|
|
-- ============================================================================
|
2024-09-16 15:36:37 +02:00
|
|
|
--changeset michael.hoennig:context-current-subject endDelimiter:--//
|
2022-08-04 17:19:45 +02:00
|
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
/*
|
2024-09-16 15:36:37 +02:00
|
|
|
Returns the current user as defined by `base.defineContext(...)`.
|
2022-08-04 17:19:45 +02:00
|
|
|
*/
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.currentSubject()
|
2022-08-04 17:19:45 +02:00
|
|
|
returns varchar(63)
|
2024-01-23 15:11:23 +01:00
|
|
|
stable -- leakproof
|
2022-08-04 17:19:45 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
declare
|
2024-09-16 15:36:37 +02:00
|
|
|
currentSubject varchar(63);
|
2022-08-04 17:19:45 +02:00
|
|
|
begin
|
|
|
|
begin
|
2024-09-16 15:36:37 +02:00
|
|
|
currentSubject := current_setting('hsadminng.currentSubject');
|
2022-08-04 17:19:45 +02:00
|
|
|
exception
|
|
|
|
when others then
|
2024-09-16 15:36:37 +02:00
|
|
|
currentSubject := null;
|
2022-08-04 17:19:45 +02:00
|
|
|
end;
|
2024-09-16 15:36:37 +02:00
|
|
|
return currentSubject;
|
2022-08-04 17:19:45 +02:00
|
|
|
end; $$;
|
|
|
|
--//
|
|
|
|
|
|
|
|
-- ============================================================================
|
2024-09-16 15:36:37 +02:00
|
|
|
--changeset michael.hoennig:context-base.ASSUMED-ROLES endDelimiter:--//
|
2022-08-04 17:19:45 +02:00
|
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Returns assumed role names as set in `hsadminng.assumedRoles`
|
|
|
|
or empty array, if not set.
|
|
|
|
*/
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.assumedRoles()
|
2024-03-28 12:15:13 +01:00
|
|
|
returns varchar(1023)[]
|
2024-01-23 15:11:23 +01:00
|
|
|
stable -- leakproof
|
2022-08-04 17:19:45 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
begin
|
2024-03-28 12:15:13 +01:00
|
|
|
return string_to_array(current_setting('hsadminng.assumedRoles', true), ';');
|
2022-08-04 17:19:45 +02:00
|
|
|
end; $$;
|
|
|
|
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.cleanIdentifier(rawIdentifier varchar)
|
2022-08-04 17:19:45 +02:00
|
|
|
returns varchar
|
|
|
|
returns null on null input
|
|
|
|
language plpgsql as $$
|
2022-08-31 09:42:40 +02:00
|
|
|
declare
|
|
|
|
cleanIdentifier varchar;
|
2022-08-04 17:19:45 +02:00
|
|
|
begin
|
2024-07-09 14:32:14 +02:00
|
|
|
cleanIdentifier := regexp_replace(rawIdentifier, '[^A-Za-z0-9\-._|]+', '', 'g');
|
2022-09-06 19:43:15 +02:00
|
|
|
return cleanIdentifier;
|
|
|
|
end; $$;
|
|
|
|
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.pureIdentifier(rawIdentifier varchar)
|
2022-09-06 19:43:15 +02:00
|
|
|
returns varchar
|
|
|
|
returns null on null input
|
|
|
|
language plpgsql as $$
|
|
|
|
declare
|
|
|
|
cleanIdentifier varchar;
|
|
|
|
begin
|
2024-09-16 15:36:37 +02:00
|
|
|
cleanIdentifier := base.cleanIdentifier(rawIdentifier);
|
2022-08-31 09:42:40 +02:00
|
|
|
if cleanIdentifier != rawIdentifier then
|
|
|
|
raise exception 'identifier "%" contains invalid characters, maybe use "%"', rawIdentifier, cleanIdentifier;
|
|
|
|
end if;
|
|
|
|
return cleanIdentifier;
|
2022-08-04 17:19:45 +02:00
|
|
|
end; $$;
|
|
|
|
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.findObjectUuidByIdName(objectTable varchar, objectIdName varchar)
|
2022-08-04 17:19:45 +02:00
|
|
|
returns uuid
|
|
|
|
returns null on null input
|
|
|
|
language plpgsql as $$
|
|
|
|
declare
|
|
|
|
sql varchar;
|
|
|
|
uuid uuid;
|
|
|
|
begin
|
2024-09-16 15:36:37 +02:00
|
|
|
objectTable := base.pureIdentifier(objectTable);
|
|
|
|
objectIdName := base.pureIdentifier(objectIdName);
|
2022-08-04 17:19:45 +02:00
|
|
|
sql := format('select * from %sUuidByIdName(%L);', objectTable, objectIdName);
|
|
|
|
begin
|
|
|
|
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 ; $$;
|
|
|
|
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.findIdNameByObjectUuid(objectTable varchar, objectUuid uuid)
|
2022-08-04 17:19:45 +02:00
|
|
|
returns varchar
|
|
|
|
returns null on null input
|
|
|
|
language plpgsql as $$
|
|
|
|
declare
|
2022-08-28 17:30:27 +02:00
|
|
|
sql varchar;
|
2022-08-04 17:19:45 +02:00
|
|
|
idName varchar;
|
|
|
|
begin
|
2024-09-16 15:36:37 +02:00
|
|
|
objectTable := base.pureIdentifier(objectTable);
|
2022-08-04 17:19:45 +02:00
|
|
|
sql := format('select * from %sIdNameByUuid(%L::uuid);', objectTable, objectUuid);
|
|
|
|
begin
|
|
|
|
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 ; $$;
|
|
|
|
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.currentSubjects()
|
2024-03-28 12:15:13 +01:00
|
|
|
returns varchar(1023)[]
|
2024-01-23 15:11:23 +01:00
|
|
|
stable -- leakproof
|
2022-08-04 17:19:45 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
declare
|
2024-03-28 12:15:13 +01:00
|
|
|
assumedRoles varchar(1023)[];
|
2022-08-04 17:19:45 +02:00
|
|
|
begin
|
2024-09-16 15:36:37 +02:00
|
|
|
assumedRoles := base.assumedRoles();
|
2022-09-06 19:43:15 +02:00
|
|
|
if array_length(assumedRoles, 1) > 0 then
|
2024-03-28 12:15:13 +01:00
|
|
|
return assumedRoles;
|
2022-08-04 17:19:45 +02:00
|
|
|
else
|
2024-09-16 15:36:37 +02:00
|
|
|
return array [base.currentSubject()]::varchar(1023)[];
|
2022-08-04 17:19:45 +02:00
|
|
|
end if;
|
|
|
|
end; $$;
|
2022-09-06 19:43:15 +02:00
|
|
|
|
2024-09-16 15:36:37 +02:00
|
|
|
create or replace function base.hasAssumedRole()
|
2022-09-06 19:43:15 +02:00
|
|
|
returns boolean
|
2024-01-23 15:11:23 +01:00
|
|
|
stable -- leakproof
|
2022-09-06 19:43:15 +02:00
|
|
|
language plpgsql as $$
|
|
|
|
begin
|
2024-09-16 15:36:37 +02:00
|
|
|
return array_length(base.assumedRoles(), 1) > 0;
|
2022-09-06 19:43:15 +02:00
|
|
|
end; $$;
|
2022-08-04 17:19:45 +02:00
|
|
|
--//
|
|
|
|
|