Files
vpd-permission-poc/database/adb/34_dds_token_data_grant_common_auth.sql

164 lines
5.0 KiB
MySQL

-- ============================================================
-- 34_dds_token_data_grant_common_auth.sql
-- Token-driven DDS enforcement using the common CB_* permission model.
--
-- This is the product-shaped DDS path:
-- 1. One local DDS END USER is used as the technical query identity.
-- 2. The application calls CB_AGENT_CTX_PKG.SET_USER_BY_BEARER(token).
-- 3. A DATA GRANT is attached to one DDS DATA ROLE on the protected VIEW.
-- 4. Its predicate function reads CB_PERMISSION / CB_PERMISSION_RULE,
-- including direct roles and active group-inherited roles.
--
-- The token is not a bind parameter in CREATE DATA GRANT syntax. It is
-- resolved before SELECT and stored in the trusted CB_AGENT_CTX namespace;
-- the DATA GRANT predicate then evaluates the common permission tables.
--
-- Prerequisite: 17_agent_ords_security_local_vpd_setup.sql,
-- 25_agent_ords_security_backoffice_support.sql,
-- 31_dds_standalone_demo_setup.sql,
-- 32_dds_vector_tag_setup.sql
-- Run as ADMIN on an Oracle AI Database release with Deep Data Security.
-- ============================================================
WHENEVER SQLERROR EXIT SQL.SQLCODE
SET ECHO ON
SET FEEDBACK ON
SET DEFINE ON
SET VERIFY OFF
PROMPT === 1. Creating one technical DDS END USER and its DATA ROLE ===
CREATE END USER IF NOT EXISTS "dds_demo_token" IDENTIFIED BY "&DDSUSER_TOKEN_PASSWORD";
BEGIN
EXECUTE IMMEDIATE 'CREATE ROLE cb_dds_token_connect_role';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -1921 THEN
RAISE;
END IF;
END;
/
GRANT CREATE SESSION TO cb_dds_token_connect_role;
CREATE DATA ROLE IF NOT EXISTS cb_dds_token_role;
GRANT cb_dds_token_connect_role TO cb_dds_token_role;
GRANT DATA ROLE cb_dds_token_role TO "dds_demo_token";
-- A DDS END USER is not a conventional database user. Standard object
-- privileges therefore go to a standard role inherited by the DATA ROLE.
GRANT EXECUTE ON admin.cb_agent_ctx_pkg TO cb_dds_token_connect_role;
PROMPT === 2. Creating the common permission predicate function ===
CREATE OR REPLACE FUNCTION admin.cb_dds_vector_tag_allowed(
p_tech_tag IN VARCHAR2
) RETURN NUMBER
AUTHID DEFINER
AS
v_user_id NUMBER;
v_allow NUMBER := 0;
v_deny NUMBER := 0;
BEGIN
BEGIN
v_user_id := TO_NUMBER(SYS_CONTEXT('CB_AGENT_CTX', 'USER_ID'));
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
IF v_user_id IS NULL OR p_tech_tag IS NULL THEN
RETURN 0;
END IF;
-- Direct roles and roles inherited from active application groups are
-- deliberately expanded at query time. CB_* remains the source of truth.
SELECT COUNT(*)
INTO v_allow
FROM (
SELECT ur.role_id
FROM cb_user_role ur
WHERE ur.user_id = v_user_id
UNION
SELECT gr.role_id
FROM cb_user_group ug
JOIN cb_app_group g
ON g.group_id = ug.group_id
AND g.active_yn = 'Y'
JOIN cb_group_role gr
ON gr.group_id = ug.group_id
WHERE ug.user_id = v_user_id
) effective_role
JOIN cb_app_user u
ON u.user_id = v_user_id
AND u.active = 'Y'
JOIN cb_permission p
ON p.role_id = effective_role.role_id
JOIN cb_permission_rule r
ON r.perm_id = p.perm_id
WHERE p.target_name = 'CB_VECTOR_SEARCH_DOCUMENTS'
AND p.action_name = 'SELECT'
AND p.permission_effect = 'ALLOW'
AND (
r.rule_type = 'ALL'
OR (
r.rule_type = 'TAG'
AND REGEXP_LIKE(
UPPER(p_tech_tag),
'(^|,)' || UPPER(TRIM(r.rule_value)) || '(,|$)'
)
)
);
SELECT COUNT(*)
INTO v_deny
FROM (
SELECT ur.role_id
FROM cb_user_role ur
WHERE ur.user_id = v_user_id
UNION
SELECT gr.role_id
FROM cb_user_group ug
JOIN cb_app_group g
ON g.group_id = ug.group_id
AND g.active_yn = 'Y'
JOIN cb_group_role gr
ON gr.group_id = ug.group_id
WHERE ug.user_id = v_user_id
) effective_role
JOIN cb_permission p
ON p.role_id = effective_role.role_id
JOIN cb_permission_rule r
ON r.perm_id = p.perm_id
WHERE p.target_name = 'CB_VECTOR_SEARCH_DOCUMENTS'
AND p.action_name = 'SELECT'
AND p.permission_effect = 'DENY'
AND r.rule_type = 'TAG'
AND REGEXP_LIKE(
UPPER(p_tech_tag),
'(^|,)' || UPPER(TRIM(r.rule_value)) || '(,|$)'
);
IF v_allow > 0 AND v_deny = 0 THEN
RETURN 1;
END IF;
RETURN 0;
END;
/
SHOW ERRORS
PROMPT === 3. Creating one object-level DATA GRANT ===
CREATE OR REPLACE DATA GRANT admin.dds_demo_token_vector_grant
AS SELECT
ON admin.cb_dds_vector_search_documents
WHERE admin.cb_dds_vector_tag_allowed(tech_tag) = 1
TO cb_dds_token_role;
PROMPT === 4. Verifying the object-level grant ===
SELECT grant_name, object_name, grantee
FROM dba_data_grants
WHERE grant_name = 'DDS_DEMO_TOKEN_VECTOR_GRANT';
PROMPT === Token-driven DDS DATA GRANT setup complete ===
PROMPT Call ADMIN.CB_AGENT_CTX_PKG.SET_USER_BY_BEARER(:token) on the
PROMPT technical connection, then SELECT from ADMIN.CB_DDS_VECTOR_SEARCH_DOCUMENTS.
EXIT;