fix(rls): not handling global permissions
This commit is contained in:
@@ -245,6 +245,12 @@ BEGIN
|
||||
|
||||
v_computed_result := morbac.is_allowed_nocache(p_user_id, p_org_id, p_activity, p_view);
|
||||
|
||||
-- NULL org_id (global-rules-only path) cannot be stored in auth_cache (org_id NOT NULL PK).
|
||||
-- Global rule changes flush the entire cache anyway, so skipping is safe.
|
||||
IF p_org_id IS NULL THEN
|
||||
RETURN v_computed_result;
|
||||
END IF;
|
||||
|
||||
BEGIN
|
||||
INSERT INTO morbac.auth_cache (user_id, org_id, activity, view, allowed, expires_at)
|
||||
VALUES (
|
||||
|
||||
+4
-6
@@ -162,17 +162,15 @@ BEGIN
|
||||
v_org_ids := morbac.current_org_ids();
|
||||
|
||||
IF v_org_ids IS NOT NULL THEN
|
||||
IF p_row_org_id IS NULL OR NOT (p_row_org_id = ANY(v_org_ids)) THEN
|
||||
IF p_row_org_id IS NOT NULL AND NOT (p_row_org_id = ANY(v_org_ids)) THEN
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
-- p_row_org_id NULL: global row — is_allowed(NULL) checks global_rules only
|
||||
RETURN morbac.is_allowed(v_user_id, p_row_org_id, p_activity, p_view);
|
||||
END IF;
|
||||
|
||||
IF p_row_org_id IS NOT NULL THEN
|
||||
RETURN morbac.is_allowed(v_user_id, p_row_org_id, p_activity, p_view);
|
||||
END IF;
|
||||
|
||||
RETURN FALSE;
|
||||
-- No org context: use row's org (or NULL for global rows — global_rules only)
|
||||
RETURN morbac.is_allowed(v_user_id, p_row_org_id, p_activity, p_view);
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
@@ -380,5 +380,9 @@ SELECT morbac.t('Karl reads GlobalTech contracts [temporal global rule, expired]
|
||||
'read', 'contracts'
|
||||
), FALSE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view = 'contracts';
|
||||
|
||||
\echo ''
|
||||
\echo '=== Global Rules Tests Completed ==='
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
-- =============================================================================
|
||||
-- rls_check Tests
|
||||
-- =============================================================================
|
||||
-- Tests morbac.rls_check() with all session-org combinations, focusing on
|
||||
-- the two cases fixed to support global rows (p_row_org_id IS NULL):
|
||||
--
|
||||
-- 1. No user_id set: always FALSE
|
||||
-- 2. Single org context
|
||||
-- a. org-scoped row, matching org
|
||||
-- b. org-scoped row, different org (blocked)
|
||||
-- c. global row (NULL org_id): uses session org
|
||||
-- 3. org_ids filter
|
||||
-- a. org-scoped row in list
|
||||
-- b. org-scoped row not in list (blocked)
|
||||
-- c. global row + global permission [was FALSE, now TRUE]
|
||||
-- d. global row + global prohibition [was FALSE, now correctly FALSE]
|
||||
-- e. global row + no rule [was FALSE, still FALSE]
|
||||
-- 4. No org context
|
||||
-- a. org-scoped row: uses row's org
|
||||
-- b. global row + global permission [was FALSE, now TRUE]
|
||||
-- c. global row + global prohibition [was FALSE, now correctly FALSE]
|
||||
-- d. global row + no rule [was FALSE, still FALSE]
|
||||
--
|
||||
-- User state carried from previous tests:
|
||||
-- Karl (30000000-0000-0000-0000-000000000011):
|
||||
-- - user_rules: read documents, read reports in GlobalTech HQ (no expiry)
|
||||
-- - no role assignments, no org memberships
|
||||
--
|
||||
-- Prerequisites: 00_setup.sql -> 14_system_principals.sql
|
||||
-- =============================================================================
|
||||
|
||||
\echo ''
|
||||
\echo '================================================================'
|
||||
\echo '15 -- RLS_CHECK'
|
||||
\echo '================================================================'
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 1: No user_id set — always FALSE
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 1. No user_id: always FALSE ---'
|
||||
|
||||
RESET morbac.user_id;
|
||||
RESET morbac.org_id;
|
||||
RESET morbac.org_ids;
|
||||
|
||||
SELECT morbac.t('rls_check without user_id, org row',
|
||||
morbac.rls_check('read', 'documents',
|
||||
'10000000-0000-0000-0000-000000000001'::uuid),
|
||||
FALSE);
|
||||
|
||||
SELECT morbac.t('rls_check without user_id, global row',
|
||||
morbac.rls_check('read', 'contracts', NULL),
|
||||
FALSE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 2: Single org context
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 2. Single org context ---'
|
||||
|
||||
SET morbac.user_id = '30000000-0000-0000-0000-000000000011'; -- Karl
|
||||
SET morbac.org_id = '10000000-0000-0000-0000-000000000001'; -- GlobalTech HQ
|
||||
|
||||
-- 2a: org-scoped row, matching org — Karl has user_rule for read documents
|
||||
SELECT morbac.t('rls_check single org, org row matches session org (Karl/documents)',
|
||||
morbac.rls_check('read', 'documents',
|
||||
'10000000-0000-0000-0000-000000000001'::uuid),
|
||||
TRUE);
|
||||
|
||||
-- 2b: org-scoped row, different org — blocked before is_allowed
|
||||
SELECT morbac.t('rls_check single org, org row from different org (blocked)',
|
||||
morbac.rls_check('read', 'documents',
|
||||
'10000000-0000-0000-0000-000000000002'::uuid),
|
||||
FALSE);
|
||||
|
||||
-- 2c: global row — uses session org, so Karl's user_rule on GlobalTech applies
|
||||
SELECT morbac.t('rls_check single org, global row (NULL org_id): uses session org',
|
||||
morbac.rls_check('read', 'documents', NULL),
|
||||
TRUE);
|
||||
|
||||
-- 2c (no permission): Karl has no rule for contracts in GlobalTech
|
||||
SELECT morbac.t('rls_check single org, global row (NULL org_id): no permission for contracts',
|
||||
morbac.rls_check('read', 'contracts', NULL),
|
||||
FALSE);
|
||||
|
||||
RESET morbac.user_id;
|
||||
RESET morbac.org_id;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 3: org_ids filter
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 3. org_ids filter ---'
|
||||
|
||||
SET morbac.user_id = '30000000-0000-0000-0000-000000000011'; -- Karl
|
||||
SET morbac.org_ids = '["10000000-0000-0000-0000-000000000001"]'; -- [GlobalTech HQ]
|
||||
|
||||
-- 3a: org-scoped row in the list — Karl has user_rule for read documents in GlobalTech
|
||||
SELECT morbac.t('rls_check org_ids, org row in list (Karl/documents/GlobalTech)',
|
||||
morbac.rls_check('read', 'documents',
|
||||
'10000000-0000-0000-0000-000000000001'::uuid),
|
||||
TRUE);
|
||||
|
||||
-- 3b: org-scoped row not in the list — blocked
|
||||
SELECT morbac.t('rls_check org_ids, org row not in list (blocked)',
|
||||
morbac.rls_check('read', 'documents',
|
||||
'10000000-0000-0000-0000-000000000002'::uuid),
|
||||
FALSE);
|
||||
|
||||
-- 3c: global row + global permission — now goes to is_allowed(Karl, NULL, ...) → global_rules 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('rls_check org_ids, global row + global permission [new: was FALSE]',
|
||||
morbac.rls_check('read', 'contracts', NULL),
|
||||
TRUE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view = 'contracts';
|
||||
|
||||
-- 3d: global row + global prohibition
|
||||
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'),
|
||||
'prohibition'
|
||||
);
|
||||
|
||||
SELECT morbac.t('rls_check org_ids, global row + global prohibition',
|
||||
morbac.rls_check('read', 'contracts', NULL),
|
||||
FALSE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view = 'contracts';
|
||||
|
||||
-- 3e: global row + no rule
|
||||
SELECT morbac.t('rls_check org_ids, global row + no rule',
|
||||
morbac.rls_check('read', 'contracts', NULL),
|
||||
FALSE);
|
||||
|
||||
RESET morbac.user_id;
|
||||
RESET morbac.org_ids;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 4: No org context
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 4. No org context ---'
|
||||
|
||||
SET morbac.user_id = '30000000-0000-0000-0000-000000000011'; -- Karl
|
||||
|
||||
-- 4a: org-scoped row — uses row's org_id (Karl has user_rule in GlobalTech)
|
||||
SELECT morbac.t('rls_check no org context, org row: uses row org (Karl/documents/GlobalTech)',
|
||||
morbac.rls_check('read', 'documents',
|
||||
'10000000-0000-0000-0000-000000000001'::uuid),
|
||||
TRUE);
|
||||
|
||||
-- 4a (no permission): Karl has no rule in Engineering
|
||||
SELECT morbac.t('rls_check no org context, org row: no permission in row org (Engineering)',
|
||||
morbac.rls_check('read', 'documents',
|
||||
'10000000-0000-0000-0000-000000000002'::uuid),
|
||||
FALSE);
|
||||
|
||||
-- 4b: global row + global permission — now goes to is_allowed(Karl, NULL, ...) → global_rules 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('rls_check no org context, global row + global permission [new: was FALSE]',
|
||||
morbac.rls_check('read', 'contracts', NULL),
|
||||
TRUE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view = 'contracts';
|
||||
|
||||
-- 4c: global row + global prohibition
|
||||
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'),
|
||||
'prohibition'
|
||||
);
|
||||
|
||||
SELECT morbac.t('rls_check no org context, global row + global prohibition',
|
||||
morbac.rls_check('read', 'contracts', NULL),
|
||||
FALSE);
|
||||
|
||||
DELETE FROM morbac.global_rules
|
||||
WHERE user_id = '30000000-0000-0000-0000-000000000011'
|
||||
AND activity = 'read' AND view = 'contracts';
|
||||
|
||||
-- 4d: global row + no rule
|
||||
SELECT morbac.t('rls_check no org context, global row + no rule',
|
||||
morbac.rls_check('read', 'contracts', NULL),
|
||||
FALSE);
|
||||
|
||||
RESET morbac.user_id;
|
||||
|
||||
\echo ''
|
||||
\echo '=== rls_check Tests Completed ==='
|
||||
Reference in New Issue
Block a user