-- ============================================================ -- 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;