1
0

rename Credentials->Profile + Context->Scope (#202)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/202
Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
Michael Hoennig
2025-09-12 11:37:55 +02:00
parent d7d77f60f3
commit bae13d5503
53 changed files with 976 additions and 1080 deletions
@@ -31,34 +31,41 @@ end; $$;
--//
-- ============================================================================
--changeset michael.hoennig:rbac-base-SUBJECT endDelimiter:--//
--changeset michael.hoennig:rbac-base-SUBJECT runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM information_schema.tables
WHERE table_schema = 'rbac' AND table_name = 'subject') THEN
*/
create table rbac.subject
(
uuid uuid primary key references rbac.reference (uuid) on delete cascade,
name varchar(63) not null unique
);
CREATE TABLE rbac.subject
(
uuid uuid primary key references rbac.reference (uuid) on delete cascade,
name varchar(63) not null unique
);
call base.create_journal('rbac.subject');
CALL base.create_journal('rbac.subject');
END IF;
END
$$;
create or replace function rbac.create_subject(subjectName varchar)
returns uuid
returns null on null input
language plpgsql as $$
declare
objectId uuid;
stableUuidNamespace uuid;
subjectUuid uuid;
begin
stableUuidNamespace := '6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid;
subjectUuid := uuid_generate_v5(stableUuidNamespace, subjectName);
insert
into rbac.reference (type)
values ('rbac.subject')
returning uuid into objectId;
into rbac.reference (uuid, type)
values (subjectUuid, 'rbac.subject');
insert
into rbac.subject (uuid, name)
values (objectid, subjectName);
return objectId;
values (subjectUuid, subjectName);
return subjectUuid;
end;
$$;
@@ -4,15 +4,15 @@
-- I presume it's a bug in Liquibase that other changeset checksums are changed by new changesets in the same file
-- ============================================================================
--changeset michael.hoennig:hs-office-person-TEST-DATA-GENERATION-FOR-CREDENTIALS context:!without-test-data endDelimiter:--//
--changeset michael.hoennig:hs-office-person-TEST-DATA-GENERATION-FOR-PROFILES context:!without-test-data runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
do language plpgsql $$
begin
call hs_office.person_create_test_data('NP', null,'Hostmaster', 'Alex');
call hs_office.person_create_test_data('NP', null, 'Hostmaster', 'Fran');
call hs_office.person_create_test_data('NP', null, 'User', 'Drew');
call hs_office.person_create_test_data('NP', null, 'User', 'Test');
call hs_office.person_create_test_data('NP', null,'Hostmaster', 'Alex', true);
call hs_office.person_create_test_data('NP', null, 'Hostmaster', 'Fran', true);
call hs_office.person_create_test_data('NP', null, 'User', 'Drew', true);
call hs_office.person_create_test_data('NP', null, 'User', 'Test', true);
end;
$$;
--//
@@ -2,7 +2,7 @@
-- ============================================================================
--changeset michael.hoennig:hs-office-person-TEST-DATA-GENERATOR endDelimiter:--//
--changeset michael.hoennig:hs-office-person-TEST-DATA-GENERATOR runOnChange:true validCheckSum:ANY endDelimiter:--//
-- ----------------------------------------------------------------------------
/*
@@ -12,7 +12,8 @@ create or replace procedure hs_office.person_create_test_data(
newPersonType hs_office.PersonType,
newTradeName varchar,
newFamilyName varchar = null,
newGivenName varchar = null
newGivenName varchar = null,
ignoreIfExists boolean = false
)
language plpgsql as $$
declare
@@ -22,7 +23,10 @@ begin
fullName := concat_ws(', ', newTradeName, newFamilyName, newGivenName);
emailAddr = 'person-' || left(base.cleanIdentifier(fullName), 32) || '@example.com';
call base.defineContext('creating person test-data');
perform rbac.create_subject(emailAddr);
if ignoreIfExists and exists (select 1 from rbac.subject where name = emailAddr) then
return;
end if;
perform rbac.create_subject(emailAddr);call base.defineContext('creating person test-data', null, emailAddr);
call base.defineContext('creating person test-data', null, emailAddr);
raise notice 'creating test person: % by %', fullName, emailAddr;
@@ -2,7 +2,7 @@
-- ============================================================================
--changeset michael.hoennig:hs-credentials-SCHEMA endDelimiter:--//
--changeset michael.hoennig:hs-profile-SCHEMA endDelimiter:--//
-- ----------------------------------------------------------------------------
CREATE SCHEMA hs_accounts;
--//
@@ -2,10 +2,10 @@
-- ============================================================================
--changeset michael.hoennig:hs-credentials-CREDENTIALS-TABLE endDelimiter:--//
--changeset michael.hoennig:hs-profile-PROFILE-TABLE endDelimiter:--//
-- ----------------------------------------------------------------------------
create table hs_accounts.credentials
create table hs_accounts.profile
(
uuid uuid PRIMARY KEY references rbac.subject (uuid) initially deferred,
version int not null default 0,
@@ -13,10 +13,8 @@ create table hs_accounts.credentials
person_uuid uuid not null references hs_office.person(uuid),
active bool,
last_used timestamp,
global_uid int unique, -- w/o
global_gid int unique, -- w/o
onboarding_token text, -- w/o, but can be set to null to invalidate
totp_secrets text[],
phone_password text,
@@ -27,10 +25,10 @@ create table hs_accounts.credentials
-- ============================================================================
--changeset michael.hoennig:hs-credentials-context-CONTEXT-TABLE endDelimiter:--//
--changeset michael.hoennig:hs-profile-scope-SCOPE-TABLE endDelimiter:--//
-- ----------------------------------------------------------------------------
create table hs_accounts.context
create table hs_accounts.scope
(
uuid uuid PRIMARY KEY,
version int not null default 0,
@@ -48,31 +46,31 @@ create table hs_accounts.context
-- ============================================================================
--changeset michael.hoennig:hs-credentials-CONTEXT-IMMUTABLE-TRIGGER endDelimiter:--//
--changeset michael.hoennig:hs-profile-SCOPE-IMMUTABLE-TRIGGER endDelimiter:--//
-- ----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION hs_accounts.prevent_context_update()
CREATE OR REPLACE FUNCTION hs_accounts.prevent_scope_update()
RETURNS TRIGGER AS $$
BEGIN
RAISE EXCEPTION 'Updates to hs_accounts.context are not allowed.';
RAISE EXCEPTION 'Updates to hs_accounts.scope are not allowed.';
END;
$$ LANGUAGE plpgsql;
-- Trigger to enforce immutability
CREATE TRIGGER context_immutable_trigger
BEFORE UPDATE ON hs_accounts.context
FOR EACH ROW EXECUTE FUNCTION hs_accounts.prevent_context_update();
CREATE TRIGGER scope_immutable_trigger
BEFORE UPDATE ON hs_accounts.scope
FOR EACH ROW EXECUTE FUNCTION hs_accounts.prevent_scope_update();
--//
-- ============================================================================
--changeset michael.hoennig:hs_accounts-CONTEXT-MAPPING endDelimiter:--//
--changeset michael.hoennig:hs_accounts-SCOPE-MAPPING endDelimiter:--//
-- ----------------------------------------------------------------------------
create table hs_accounts.context_mapping
create table hs_accounts.scope_mapping
(
uuid uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
credentials_uuid uuid references hs_accounts.credentials(uuid) ON DELETE CASCADE,
context_uuid uuid references hs_accounts.context(uuid) ON DELETE RESTRICT
profile_uuid uuid references hs_accounts.profile(uuid) ON DELETE CASCADE,
scope_uuid uuid references hs_accounts.scope(uuid) ON DELETE RESTRICT
);
--//
@@ -81,16 +79,16 @@ create table hs_accounts.context_mapping
--changeset michael.hoennig:hs-hs_accounts-JOURNALS endDelimiter:--//
-- ----------------------------------------------------------------------------
call base.create_journal('hs_accounts.context_mapping');
call base.create_journal('hs_accounts.context');
call base.create_journal('hs_accounts.credentials');
call base.create_journal('hs_accounts.scope_mapping');
call base.create_journal('hs_accounts.scope');
call base.create_journal('hs_accounts.profile');
--//
-- ============================================================================
--changeset michael.hoennig:hs_accounts-HISTORICIZATION endDelimiter:--//
-- ----------------------------------------------------------------------------
call base.tx_create_historicization('hs_accounts.context_mapping');
call base.tx_create_historicization('hs_accounts.context');
call base.tx_create_historicization('hs_accounts.credentials');
call base.tx_create_historicization('hs_accounts.scope_mapping');
call base.tx_create_historicization('hs_accounts.scope');
call base.tx_create_historicization('hs_accounts.profile');
--//
@@ -1,41 +0,0 @@
### rbac credentialsContext
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
```mermaid
%%{init:{'flowchart':{'htmlLabels':false}}}%%
flowchart TB
subgraph credentialsContext["`**credentialsContext**`"]
direction TB
style credentialsContext fill:#dd4901,stroke:#274d6e,stroke-width:8px
subgraph credentialsContext:roles[ ]
style credentialsContext:roles fill:#dd4901,stroke:white
role:credentialsContext:OWNER[[credentialsContext:OWNER]]
role:credentialsContext:ADMIN[[credentialsContext:ADMIN]]
role:credentialsContext:REFERRER[[credentialsContext:REFERRER]]
end
subgraph credentialsContext:permissions[ ]
style credentialsContext:permissions fill:#dd4901,stroke:white
perm:credentialsContext:INSERT{{credentialsContext:INSERT}}
perm:credentialsContext:UPDATE{{credentialsContext:UPDATE}}
perm:credentialsContext:DELETE{{credentialsContext:DELETE}}
perm:credentialsContext:SELECT{{credentialsContext:SELECT}}
end
end
%% granting roles to roles
role:credentialsContext:OWNER ==> role:credentialsContext:ADMIN
role:credentialsContext:ADMIN ==> role:credentialsContext:REFERRER
%% granting permissions to roles
role:rbac.global:ADMIN ==> perm:credentialsContext:INSERT
role:rbac.global:ADMIN ==> perm:credentialsContext:UPDATE
role:rbac.global:ADMIN ==> perm:credentialsContext:DELETE
role:rbac.global:REFERRER ==> perm:credentialsContext:SELECT
```
@@ -0,0 +1,41 @@
### rbac profileContext
This code generated was by RbacViewMermaidFlowchartGenerator, do not amend manually.
```mermaid
%%{init:{'flowchart':{'htmlLabels':false}}}%%
flowchart TB
subgraph profileContext["`**profileContext**`"]
direction TB
style profileContext fill:#dd4901,stroke:#274d6e,stroke-width:8px
subgraph profileContext:roles[ ]
style profileContext:roles fill:#dd4901,stroke:white
role:profileContext:OWNER[[profileContext:OWNER]]
role:profileContext:ADMIN[[profileContext:ADMIN]]
role:profileContext:REFERRER[[profileContext:REFERRER]]
end
subgraph profileContext:permissions[ ]
style profileContext:permissions fill:#dd4901,stroke:white
perm:profileContext:INSERT{{profileContext:INSERT}}
perm:profileContext:UPDATE{{profileContext:UPDATE}}
perm:profileContext:DELETE{{profileContext:DELETE}}
perm:profileContext:SELECT{{profileContext:SELECT}}
end
end
%% granting roles to roles
role:profileContext:OWNER ==> role:profileContext:ADMIN
role:profileContext:ADMIN ==> role:profileContext:REFERRER
%% granting permissions to roles
role:rbac.global:ADMIN ==> perm:profileContext:INSERT
role:rbac.global:ADMIN ==> perm:profileContext:UPDATE
role:rbac.global:ADMIN ==> perm:profileContext:DELETE
role:rbac.global:REFERRER ==> perm:profileContext:SELECT
```
@@ -2,7 +2,7 @@
-- ============================================================================
--changeset michael.hoennig:hs_accounts-credentials-TEST-DATA context:!without-test-data endDelimiter:--//
--changeset michael.hoennig:hs_accounts-profile-TEST-DATA context:!without-test-data endDelimiter:--//
-- ----------------------------------------------------------------------------
do language plpgsql $$
@@ -16,11 +16,11 @@ declare
personDrewUuid uuid;
context_HSADMIN_prod hs_accounts.context;
context_SSH_internal hs_accounts.context;
context_SSH_external hs_accounts.context;
context_MATRIX_internal hs_accounts.context;
context_MATRIX_external hs_accounts.context;
scope_HSADMIN_prod hs_accounts.scope;
scope_SSH_internal hs_accounts.scope;
scope_SSH_external hs_accounts.scope;
scope_MATRIX_internal hs_accounts.scope;
scope_MATRIX_external hs_accounts.scope;
begin
call base.defineContext('creating booking-project test-data', null, 'superuser-alex@hostsharing.net', 'rbac.global#global:ADMIN');
@@ -32,28 +32,28 @@ begin
userDrewSubjectUuid = (SELECT uuid FROM rbac.subject WHERE name='selfregistered-user-drew@hostsharing.org');
personDrewUuid = (SELECT uuid FROM hs_office.person WHERE givenName='Drew');
-- Add test contexts
INSERT INTO hs_accounts.context (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
-- Add test scopes
INSERT INTO hs_accounts.scope (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
('11111111-1111-1111-1111-111111111111', 'HSADMIN', 'prod', true, true)
RETURNING * INTO context_HSADMIN_prod;
INSERT INTO hs_accounts.context (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
RETURNING * INTO scope_HSADMIN_prod;
INSERT INTO hs_accounts.scope (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
('22222222-2222-2222-2222-222222222222', 'SSH', 'internal', true, false)
RETURNING * INTO context_SSH_internal;
INSERT INTO hs_accounts.context (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
RETURNING * INTO scope_SSH_internal;
INSERT INTO hs_accounts.scope (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
('33333333-3333-3333-3333-333333333333', 'SSH', 'external', false, true)
RETURNING * INTO context_SSH_external;
INSERT INTO hs_accounts.context (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
RETURNING * INTO scope_SSH_external;
INSERT INTO hs_accounts.scope (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
('44444444-4444-4444-4444-444444444444', 'MATRIX', 'internal', true, false)
RETURNING * INTO context_MATRIX_internal;
INSERT INTO hs_accounts.context (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
RETURNING * INTO scope_MATRIX_internal;
INSERT INTO hs_accounts.scope (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
('55555555-5555-5555-5555-555555555555', 'MATRIX', 'external', true, true)
RETURNING * INTO context_MATRIX_external;
INSERT INTO hs_accounts.context (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
RETURNING * INTO scope_MATRIX_external;
INSERT INTO hs_accounts.scope (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
('66666666-6666-6666-6666-666666666666', 'MASTODON', 'external', false, true);
INSERT INTO hs_accounts.context (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
INSERT INTO hs_accounts.scope (uuid, type, qualifier, only_for_natural_persons, public_access) VALUES
('77777777-7777-7777-7777-777777777777', 'BBB', 'external', false, true);
-- grant general access to public credential contexts
-- grant general access to public credential scopes
-- TODO_impl: RBAC rules for _rv do not yet work properly
-- call rbac.grantPermissiontoRole(
-- rbac.createPermission(context_HSADMIN_prod.uuid, 'SELECT'),
@@ -64,25 +64,25 @@ begin
-- call rbac.grantPermissionToRole(
-- rbac.createPermission(context_MATRIX_internal.uuid, 'SELECT'),
-- rbac.global_ADMIN());
-- call rbac.grantRoleToRole(hs_accounts.context_REFERRER(context_SSH_internal), rbac.global_ADMIN());
-- call rbac.grantRoleToRole(hs_accounts.context_REFERRER(context_MATRIX_internal), rbac.global_ADMIN());
-- call rbac.grantRoleToRole(hs_accounts.scope_REFERRER(context_SSH_internal), rbac.global_ADMIN());
-- call rbac.grantRoleToRole(hs_accounts.scope_REFERRER(context_MATRIX_internal), rbac.global_ADMIN());
-- Add test credentials (linking to assumed rbac.subject UUIDs)
INSERT INTO hs_accounts.credentials (uuid, version, person_uuid, active, global_uid, global_gid, onboarding_token, totp_secrets, phone_password, email_address, sms_number) VALUES
( superuserAlexSubjectUuid, 0, personAlexUuid, true, 1001, 1001, 'token-abc', ARRAY['otp-secret-1a', 'otp-secret-1b'], 'phone-pw-1', 'alex@example.com', '111-222-3333'),
( superuserFranSubjectUuid, 0, personFranUuid, true, 1002, 1002, 'token-def', ARRAY['otp-secret-2'], 'phone-pw-2', 'fran@example.com', '444-555-6666'),
( userDrewSubjectUuid, 0, personDrewUuid, true, 1003, 1003, 'token-def', ARRAY['otp-secret-3'], 'phone-pw-3', 'drew@example.org', '999-888-7777');
-- Add test profile (linking to assumed rbac.subject UUIDs)
INSERT INTO hs_accounts.profile (uuid, version, person_uuid, active, global_uid, global_gid, totp_secrets, phone_password, email_address, sms_number) VALUES
( superuserAlexSubjectUuid, 0, personAlexUuid, true, 1001, 1001, ARRAY['otp-secret-1a', 'otp-secret-1b'], 'phone-pw-1', 'alex@example.com', '111-222-3333'),
( superuserFranSubjectUuid, 0, personFranUuid, true, 1002, 1002, ARRAY['otp-secret-2'], 'phone-pw-2', 'fran@example.com', '444-555-6666'),
( userDrewSubjectUuid, 0, personDrewUuid, true, 1003, 1003, ARRAY['otp-secret-3'], 'phone-pw-3', 'drew@example.org', '999-888-7777');
-- Map credentials to contexts
INSERT INTO hs_accounts.context_mapping (credentials_uuid, context_uuid) VALUES
(superuserAlexSubjectUuid, context_HSADMIN_prod.uuid),
(superuserFranSubjectUuid, context_HSADMIN_prod.uuid),
(userDrewSubjectUuid, context_HSADMIN_prod.uuid),
(superuserAlexSubjectUuid, context_SSH_internal.uuid),
(superuserFranSubjectUuid, context_SSH_internal.uuid),
(userDrewSubjectUuid, context_SSH_external.uuid),
(superuserAlexSubjectUuid, context_MATRIX_internal.uuid),
(superuserFranSubjectUuid, context_MATRIX_internal.uuid);
-- Map profile to contexts
INSERT INTO hs_accounts.scope_mapping (profile_uuid, scope_uuid) VALUES
(superuserAlexSubjectUuid, scope_HSADMIN_prod.uuid),
(superuserFranSubjectUuid, scope_HSADMIN_prod.uuid),
(userDrewSubjectUuid, scope_HSADMIN_prod.uuid),
(superuserAlexSubjectUuid, scope_SSH_internal.uuid),
(superuserFranSubjectUuid, scope_SSH_internal.uuid),
(userDrewSubjectUuid, scope_SSH_external.uuid),
(superuserAlexSubjectUuid, scope_MATRIX_internal.uuid),
(superuserFranSubjectUuid, scope_MATRIX_internal.uuid);
end; $$;
--//