164 lines
5.0 KiB
MySQL
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;
|