feat(system): introduce global rules and system principals for easier system account handling
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
-- =============================================================================
|
||||
-- Global Rules Tests
|
||||
-- =============================================================================
|
||||
-- Tests system-wide rules via morbac.global_rules.
|
||||
--
|
||||
-- Scenarios:
|
||||
-- 1. No global rule: Karl (no role) is denied by default
|
||||
-- 2. Global permission (user_id=NULL): all users gain access
|
||||
-- 3. Global permission (user_id=uuid): only that user gains access
|
||||
-- 4. Global prohibition (user_id=NULL): all users are denied regardless of role
|
||||
-- 5. Global prohibition (user_id=uuid): only that user is denied
|
||||
-- 6. Priority: global permission with higher priority overrides global prohibition
|
||||
-- 7. Priority: high-priority global prohibition overrides role-based permission
|
||||
-- 8. NULL activity/view wildcards (no hierarchy needed)
|
||||
-- 9. Activity/view hierarchy applies when activity/view are set
|
||||
-- 10. Temporal global rules (valid_from / valid_until)
|
||||
--
|
||||
-- Prerequisites: 00_setup.sql -> 12_user_rules.sql
|
||||
-- =============================================================================
|
||||
|
||||
\echo ''
|
||||
\echo '================================================================'
|
||||
\echo '13 -- GLOBAL RULES'
|
||||
\echo '================================================================'
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 1: No global rule -- Karl (no role) is denied
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 1. No global rule: access denied ---'
|
||||
|
||||
SELECT morbac.t('Karl (no role) reads GlobalTech contracts [no global rule]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'contracts'
|
||||
), FALSE);
|
||||
|
||||
SELECT morbac.t('Karl (no role) reads Engineering contracts [no global rule]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000002'::uuid,
|
||||
'read', 'contracts'
|
||||
), FALSE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 2: Global permission (user_id=NULL) -- all users gain access
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 2. Global permission, user_id=NULL: all users ---'
|
||||
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
NULL,
|
||||
'read', 'contracts',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
-- Karl (no role) can now read contracts in any org
|
||||
SELECT morbac.t('Karl reads GlobalTech contracts [global permission, any user]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
SELECT morbac.t('Karl reads Engineering contracts [global permission covers all orgs]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000002'::uuid,
|
||||
'read', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
-- Dave (employee) also benefits
|
||||
SELECT morbac.t('Dave reads GlobalTech contracts [global permission, any user]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
DELETE FROM morbac.global_rules WHERE user_id IS NULL AND activity = 'read' AND view = 'contracts';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 3: Global permission (user_id=uuid) -- specific user only
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 3. Global permission, user_id=Karl only ---'
|
||||
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'30000000-0000-0000-0000-000000000011', -- Karl
|
||||
'read', 'contracts',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
SELECT morbac.t('Karl reads GlobalTech contracts [user_id-specific global permission]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
-- Dave has no role permission on contracts and no global rule for him
|
||||
SELECT morbac.t('Dave reads GlobalTech contracts [user_id-specific rule does not cover Dave]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'contracts'
|
||||
), FALSE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view = 'contracts';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 4: Global prohibition (user_id=NULL) -- all users denied regardless of role
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 4. Global prohibition, user_id=NULL: all users denied ---'
|
||||
|
||||
-- Dave (employee) has a role-based permission on public_data from setup
|
||||
SELECT morbac.t('Dave reads GlobalTech public_data [role permission before global prohibition]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), TRUE);
|
||||
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
NULL,
|
||||
'read', 'public_data',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'prohibition'
|
||||
);
|
||||
|
||||
SELECT morbac.t('Dave reads GlobalTech public_data [global prohibition blocks role permission]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), FALSE);
|
||||
|
||||
-- Karl (no role) is also denied
|
||||
SELECT morbac.t('Karl reads GlobalTech public_data [global prohibition, no role]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), FALSE);
|
||||
|
||||
-- Alice (CEO, highest role) is also denied
|
||||
SELECT morbac.t('Alice reads GlobalTech public_data [global prohibition overrides CEO role]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000001'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), FALSE);
|
||||
|
||||
DELETE FROM morbac.global_rules WHERE user_id IS NULL AND activity = 'read' AND view = 'public_data';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 5: Global prohibition (user_id=uuid) -- specific user denied only
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 5. Global prohibition, user_id=Dave only ---'
|
||||
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'30000000-0000-0000-0000-000000000004', -- Dave
|
||||
'read', 'public_data',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'prohibition'
|
||||
);
|
||||
|
||||
SELECT morbac.t('Dave reads GlobalTech public_data [user_id-specific global prohibition]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), FALSE);
|
||||
|
||||
-- Carol (manager) is unaffected
|
||||
SELECT morbac.t('Carol reads GlobalTech public_data [global prohibition does not affect Carol]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000003'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), TRUE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000004'
|
||||
AND activity = 'read' AND view = 'public_data';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 6: Priority -- global permission overrides global prohibition
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 6. Priority: global permission > global prohibition ---'
|
||||
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, priority)
|
||||
VALUES (
|
||||
NULL,
|
||||
'read', 'public_data',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'prohibition', 5
|
||||
);
|
||||
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, priority)
|
||||
VALUES (
|
||||
'30000000-0000-0000-0000-000000000004', -- Dave
|
||||
'read', 'public_data',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission', 10
|
||||
);
|
||||
|
||||
SELECT morbac.t('Dave reads GlobalTech public_data [priority-10 global permission beats priority-5 global prohibition]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), TRUE);
|
||||
|
||||
-- Karl has no user_id-specific permission -- global prohibition still blocks him
|
||||
SELECT morbac.t('Karl reads GlobalTech public_data [global prohibition still blocks non-exempted user]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), FALSE);
|
||||
|
||||
DELETE FROM morbac.global_rules WHERE activity = 'read' AND view = 'public_data';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 7: Priority -- high-priority global prohibition overrides role permission
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 7. Priority: global prohibition > role permission ---'
|
||||
|
||||
-- Dave has role-based read on public_data (priority 0 by default)
|
||||
SELECT morbac.t('Dave reads GlobalTech public_data [role permission, no global rule]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), TRUE);
|
||||
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, priority)
|
||||
VALUES (
|
||||
NULL,
|
||||
'read', 'public_data',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'prohibition', 100
|
||||
);
|
||||
|
||||
SELECT morbac.t('Dave reads GlobalTech public_data [priority-100 global prohibition beats role permission]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'public_data'
|
||||
), FALSE);
|
||||
|
||||
DELETE FROM morbac.global_rules WHERE activity = 'read' AND view = 'public_data';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 8: NULL activity/view wildcards
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 8. NULL wildcards: activity=NULL and view=NULL ---'
|
||||
|
||||
-- view=NULL grants read on every view for Karl (no role)
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'30000000-0000-0000-0000-000000000011', -- Karl
|
||||
'read', NULL,
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
SELECT morbac.t('Karl reads GlobalTech contracts [view=NULL global permission]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
SELECT morbac.t('Karl reads GlobalTech financial_data [view=NULL global permission]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'financial_data'
|
||||
), TRUE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view IS NULL;
|
||||
|
||||
-- activity=NULL and view=NULL grants everything
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'30000000-0000-0000-0000-000000000011', -- Karl
|
||||
NULL, NULL,
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
SELECT morbac.t('Karl deletes GlobalTech contracts [activity=NULL, view=NULL global permission]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'delete', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity IS NULL AND view IS NULL;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 9: Activity/view hierarchy applies when activity/view are set
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 9. Activity/view hierarchy ---'
|
||||
|
||||
-- financial_data is a child of documents (view hierarchy from setup)
|
||||
-- A global permission on 'documents' should cover 'financial_data'
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'30000000-0000-0000-0000-000000000011', -- Karl
|
||||
'read', 'documents',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
SELECT morbac.t('Karl reads GlobalTech financial_data [global permission on documents covers child view]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'financial_data'
|
||||
), TRUE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view = 'documents';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 10: Temporal global rules
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 10. Temporal global rules ---'
|
||||
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, valid_from, valid_until)
|
||||
VALUES (
|
||||
'30000000-0000-0000-0000-000000000011', -- Karl
|
||||
'read', 'contracts',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission',
|
||||
now() - interval '1 hour',
|
||||
now() + interval '1 day'
|
||||
);
|
||||
|
||||
SELECT morbac.t('Karl reads GlobalTech contracts [temporal global rule, active]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
UPDATE morbac.global_rules
|
||||
SET valid_until = now() - interval '1 second'
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view = 'contracts';
|
||||
|
||||
SELECT morbac.t('Karl reads GlobalTech contracts [temporal global rule, expired]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'contracts'
|
||||
), FALSE);
|
||||
|
||||
\echo ''
|
||||
\echo '=== Global Rules Tests Completed ==='
|
||||
@@ -0,0 +1,293 @@
|
||||
-- =============================================================================
|
||||
-- System Principals Tests
|
||||
-- =============================================================================
|
||||
-- Tests the morbac.system_principals registry and all associated protections.
|
||||
--
|
||||
-- Scenarios:
|
||||
-- 1. Setup: register a system principal and define its permissions via global_rules
|
||||
-- 2. Permissions work normally (system principal can access what it is granted)
|
||||
-- 3. Prohibitions are ignored (no role-based, user-level, or global prohibition applies)
|
||||
-- 4. Cannot assign roles to a system principal
|
||||
-- 5. Cannot revoke roles from a system principal
|
||||
-- 6. Cannot add negative role assignments for a system principal
|
||||
-- 7. Cannot add user_rules for a system principal
|
||||
-- 8. Cannot create delegations involving a system principal
|
||||
-- 9. Cannot add a targeted global_rules prohibition for a system principal
|
||||
-- 10. Cannot modify or delete existing global_rules for a system principal
|
||||
--
|
||||
-- Prerequisites: 00_setup.sql -> 13_global_rules.sql
|
||||
-- =============================================================================
|
||||
|
||||
\echo ''
|
||||
\echo '================================================================'
|
||||
\echo '14 -- SYSTEM PRINCIPALS'
|
||||
\echo '================================================================'
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 1: Setup
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 1. Setup ---'
|
||||
|
||||
-- Register a system principal (done as DB owner at deploy time)
|
||||
INSERT INTO morbac.system_principals (user_id, description)
|
||||
VALUES (
|
||||
'40000000-0000-0000-0000-000000000001',
|
||||
'Backend API service account'
|
||||
);
|
||||
|
||||
-- Define its permissions via global_rules (immutable once inserted)
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'40000000-0000-0000-0000-000000000001',
|
||||
NULL, NULL,
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
SELECT morbac.t('System principal registered',
|
||||
EXISTS (SELECT 1 FROM morbac.system_principals WHERE user_id = '40000000-0000-0000-0000-000000000001'),
|
||||
TRUE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 2: Permissions work
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 2. System principal permissions are effective ---'
|
||||
|
||||
SELECT morbac.t('System principal reads GlobalTech documents [global permission, activity=NULL view=NULL]',
|
||||
morbac.is_allowed_nocache(
|
||||
'40000000-0000-0000-0000-000000000001'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'documents'
|
||||
), TRUE);
|
||||
|
||||
SELECT morbac.t('System principal deletes Engineering contracts [global permission covers all]',
|
||||
morbac.is_allowed_nocache(
|
||||
'40000000-0000-0000-0000-000000000001'::uuid,
|
||||
'10000000-0000-0000-0000-000000000002'::uuid,
|
||||
'delete', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 3: Prohibitions are ignored
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 3. Prohibitions are ignored for system principals ---'
|
||||
|
||||
-- Insert a blanket global prohibition (user_id=NULL affects everyone normally)
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, priority)
|
||||
VALUES (
|
||||
NULL,
|
||||
'delete', 'contracts',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'prohibition', 999
|
||||
);
|
||||
|
||||
SELECT morbac.t('System principal deletes contracts [blanket global prohibition ignored]',
|
||||
morbac.is_allowed_nocache(
|
||||
'40000000-0000-0000-0000-000000000001'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'delete', 'contracts'
|
||||
), TRUE);
|
||||
|
||||
-- Regular user is still affected by the prohibition
|
||||
SELECT morbac.t('Dave deletes GlobalTech contracts [blanket prohibition applies to regular users]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'delete', 'contracts'
|
||||
), FALSE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id IS NULL AND activity = 'delete' AND view = 'contracts';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 4: Cannot assign roles to a system principal
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 4. Role assignment blocked ---'
|
||||
|
||||
SELECT morbac.t('Assigning role to system principal raises exception',
|
||||
(SELECT COUNT(*) FROM (
|
||||
SELECT morbac.assign_role(
|
||||
'40000000-0000-0000-0000-000000000001'::uuid,
|
||||
(SELECT id FROM morbac.roles WHERE name = 'employee' AND org_id = '10000000-0000-0000-0000-000000000001'),
|
||||
'10000000-0000-0000-0000-000000000001'::uuid
|
||||
)
|
||||
) sub) = 0,
|
||||
FALSE
|
||||
) WHERE FALSE; -- skip, tested via exception below
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
INSERT INTO morbac.user_roles (user_id, role_id, org_id)
|
||||
VALUES (
|
||||
'40000000-0000-0000-0000-000000000001',
|
||||
(SELECT id FROM morbac.roles WHERE name = 'employee' AND org_id = '10000000-0000-0000-0000-000000000001'),
|
||||
'10000000-0000-0000-0000-000000000001'
|
||||
);
|
||||
RAISE EXCEPTION 'expected exception not raised';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLERRM LIKE '%system principal%' THEN
|
||||
RAISE NOTICE 'PASS: role assignment to system principal blocked';
|
||||
ELSE
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 5: Cannot add negative role assignments for a system principal
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 5. Negative role assignment blocked ---'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
INSERT INTO morbac.negative_role_assignments (user_id, role_id, org_id)
|
||||
VALUES (
|
||||
'40000000-0000-0000-0000-000000000001',
|
||||
(SELECT id FROM morbac.roles WHERE name = 'employee' AND org_id = '10000000-0000-0000-0000-000000000001'),
|
||||
'10000000-0000-0000-0000-000000000001'
|
||||
);
|
||||
RAISE EXCEPTION 'expected exception not raised';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLERRM LIKE '%system principal%' THEN
|
||||
RAISE NOTICE 'PASS: negative role assignment for system principal blocked';
|
||||
ELSE
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 6: Cannot add user_rules for a system principal
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 6. user_rules blocked ---'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
INSERT INTO morbac.user_rules (user_id, org_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'40000000-0000-0000-0000-000000000001',
|
||||
'10000000-0000-0000-0000-000000000001',
|
||||
'read', 'documents',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
RAISE EXCEPTION 'expected exception not raised';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLERRM LIKE '%system principal%' THEN
|
||||
RAISE NOTICE 'PASS: user_rules insert for system principal blocked';
|
||||
ELSE
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 7: Cannot create delegations involving a system principal
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 7. Delegations blocked ---'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
INSERT INTO morbac.delegations (delegator_id, delegatee_id, role_id, org_id)
|
||||
VALUES (
|
||||
'30000000-0000-0000-0000-000000000001', -- Alice as delegator
|
||||
'40000000-0000-0000-0000-000000000001', -- system principal as delegatee
|
||||
(SELECT id FROM morbac.roles WHERE name = 'employee' AND org_id = '10000000-0000-0000-0000-000000000001'),
|
||||
'10000000-0000-0000-0000-000000000001'
|
||||
);
|
||||
RAISE EXCEPTION 'expected exception not raised';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLERRM LIKE '%system principal%' THEN
|
||||
RAISE NOTICE 'PASS: delegation to system principal blocked';
|
||||
ELSE
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 8: Cannot add a targeted global_rules prohibition
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 8. Targeted global prohibition blocked ---'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'40000000-0000-0000-0000-000000000001',
|
||||
'delete', 'contracts',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'prohibition'
|
||||
);
|
||||
RAISE EXCEPTION 'expected exception not raised';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLERRM LIKE '%system principal%' THEN
|
||||
RAISE NOTICE 'PASS: global prohibition targeting system principal blocked';
|
||||
ELSE
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 9: Cannot add a permission global_rule for a system principal
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 9. New global permission for system principal blocked ---'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'40000000-0000-0000-0000-000000000001',
|
||||
'read', 'documents',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
RAISE EXCEPTION 'expected exception not raised';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLERRM LIKE '%system principal%' THEN
|
||||
RAISE NOTICE 'PASS: new global permission for system principal blocked (define at deploy time only)';
|
||||
ELSE
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 10: Cannot delete existing global_rules for a system principal
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 10. Deleting system principal global_rules blocked ---'
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '40000000-0000-0000-0000-000000000001';
|
||||
RAISE EXCEPTION 'expected exception not raised';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLERRM LIKE '%system principal%' THEN
|
||||
RAISE NOTICE 'PASS: deletion of system principal global rules blocked';
|
||||
ELSE
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
\echo ''
|
||||
\echo '=== System Principals Tests Completed ==='
|
||||
Reference in New Issue
Block a user