1
0
Files
hs.hsadmin.ng/src/main/resources/db/changelog/1-rbac/1080-rbac-global.sql
T

236 lines
8.7 KiB
PL/PgSQL

--liquibase formatted sql
-- ============================================================================
--changeset michael.hoennig:rbac-global-OBJECT runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
The purpose of this table is provide root business objects
which can be referenced from global roles.
Without this table, these columns needed to be nullable and
many queries would be more complicated.
In production databases, there is only a single row in this table,
in test stages, there can be one row for each test data realm.
*/
create table if not exists rbac.global
(
uuid uuid primary key references rbac.object (uuid) on delete cascade,
name varchar(63) unique
);
create unique index if not exists Global_Singleton on rbac.global ((0));
grant select on rbac.global to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
--//
-- ============================================================================
--changeset michael.hoennig:rbac-global-IS-GLOBAL-ADMIN runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ------------------------------------------------------------------
create or replace function rbac.isGlobalAdmin()
returns boolean
language plpgsql as $$
declare
isGlobalAdmin text;
begin
isGlobalAdmin := current_setting('hsadminng.isGlobalAdmin', true);
if isGlobalAdmin is not null then
return isGlobalAdmin::boolean;
end if;
raise exception '`hsadminng.isGlobalAdmin` should have been set by `rbac.defineContext()`';
end; $$;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-global-HAS-GLOBAL-ADMIN-ROLE runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Returns true if the current user is a global admin and has no assumed role.
ATTENTION: It's false if the global-admin role is assumed,
because the global admin role does not have the global admin role, but it is the global admin role.
The differentiation is important for the cases where this function is used.
*/
create or replace function rbac.hasGlobalAdminRole()
returns boolean
stable -- leakproof
language plpgsql as $$
declare
assumedRoles text;
begin
begin
assumedRoles := current_setting('hsadminng.assumedRoles');
exception
when others then
assumedRoles := null;
end;
return TRIM(COALESCE(assumedRoles, '')) = '' and rbac.isGlobalAdmin();
end; $$;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-global-HAS-GLOBAL-PERMISSION endDelimiter:--//
-- ------------------------------------------------------------------
create or replace function rbac.hasGlobalPermission(op rbac.RbacOp)
returns boolean
language sql as
$$
-- TODO.perf: this could to be optimized
select (select uuid from rbac.global) in
(select rbac.queryAccessibleObjectUuidsOfSubjectIds(op, 'rbac.global', rbac.currentSubjectOrAssumedRolesUuids()));
$$;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-global-IDENTITY-VIEW runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Creates a view to the rbac.global object table which maps the identifying name to the objectUuid.
*/
create or replace view rbac.global_iv as
select target.uuid, target.name as idName
from rbac.global as target;
grant all privileges on rbac.global_iv to ${HSADMINNG_POSTGRES_RESTRICTED_USERNAME};
/*
Returns the objectUuid for a given identifying name (in this case the idName).
*/
create or replace function rbac.global_uuid_by_id_name(idName varchar)
returns uuid
language sql
strict as $$
select uuid from rbac.global_iv iv where iv.idName = global_uuid_by_id_name.idName;
$$;
/*
Returns the identifying name for a given objectUuid (in this case the idName).
*/
create or replace function rbac.global_id_name_by_uuid(uuid uuid)
returns varchar
language sql
strict as $$
select idName from rbac.global_iv iv where iv.uuid = global_id_name_by_uuid.uuid;
$$;
--//
--liquibase formatted sql
-- ============================================================================
--changeset michael.hoennig:rbac-global-PSEUDO-OBJECT endDelimiter:--//
-- ----------------------------------------------------------------------------
/**
A single row to be referenced as a rbac.Global object.
*/
begin transaction;
call base.defineContext('initializing table "rbac.global"', null, null, null);
insert
into rbac.object (objecttable) values ('rbac.global');
insert
into rbac.global (uuid, name) values ((select uuid from rbac.object where objectTable = 'rbac.global'), 'global');
commit;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-global-ADMIN-ROLE endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
A rbac.Global administrator role.
*/
create or replace function rbac.global_ADMIN(assumed boolean = true)
returns rbac.RoleDescriptor
returns null on null input
stable -- leakproof
language sql as $$
select 'rbac.global', (select uuid from rbac.object where objectTable = 'rbac.global'), 'ADMIN'::rbac.RoleType, assumed;
$$;
begin transaction;
call base.defineContext('creating role:rbac.global#global:ADMIN', null, null, null);
select rbac.createRole(rbac.global_ADMIN());
commit;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-global-GUEST-ROLE runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
A rbac.Global guest role.
*/
create or replace function rbac.global_GUEST(assumed boolean = true)
returns rbac.RoleDescriptor
returns null on null input
stable -- leakproof
language sql as $$
select 'rbac.global', (select uuid from rbac.object where objectTable = 'rbac.global'), 'GUEST'::rbac.RoleType, assumed;
$$;
do language plpgsql $$
begin
call base.defineContext('creating role:rbac.global#global:guest', null, null, null);
begin
perform rbac.createRole(rbac.global_GUEST());
exception
when unique_violation then
null; -- ignore if it already exists from prev execution of this changeset
end;
end;
$$;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-global-ADMIN-USERS context:!without-test-data endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Create two users and assign both to the administrators' role.
*/
do language plpgsql $$
declare
admins uuid ;
begin
call base.defineContext('creating fake test-realm admin users', null, null, null);
admins = rbac.findRoleId(rbac.global_ADMIN());
call rbac.grantRoleToSubjectUnchecked(admins, admins, rbac.create_subject('superuser-alex@hostsharing.net'));
call rbac.grantRoleToSubjectUnchecked(admins, admins, rbac.create_subject('superuser-fran@hostsharing.net'));
perform rbac.create_subject('selfregistered-user-drew@hostsharing.org');
perform rbac.create_subject('selfregistered-test-user@hostsharing.org');
end;
$$;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-global-TEST context:!without-test-data runAlways:true endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
Tests if rbac.currentSubjectUuid() can fetch the user from the session variable.
*/
do language plpgsql $$
declare
userName varchar;
begin
call base.defineContext('testing currentSubjectUuid', null, 'superuser-fran@hostsharing.net', null);
select userName from rbac.subject where uuid = rbac.currentSubjectUuid() into userName;
if userName <> 'superuser-fran@hostsharing.net' then
raise exception 'setting or fetching initial currentSubject failed, got: %', userName;
end if;
call base.defineContext('testing currentSubjectUuid', null, 'superuser-alex@hostsharing.net', null);
select userName from rbac.subject where uuid = rbac.currentSubjectUuid() into userName;
if userName = 'superuser-alex@hostsharing.net' then
raise exception 'currentSubject should not change in one transaction, but did change, got: %', userName;
end if;
end; $$;
--//