[Developer] #567 record actual VPD execution with FGA

This commit is contained in:
devmrko
2026-07-01 16:02:03 +09:00
parent 57d77d2df2
commit ebcce66bf7
17 changed files with 532 additions and 220 deletions

View File

@@ -19,7 +19,10 @@ SET FEEDBACK ON
PROMPT === Creating CB_ORDS handler package ===
CREATE OR REPLACE PACKAGE cb_ords_handler_pkg AUTHID DEFINER AS
PROCEDURE set_vpd_context(p_authorization IN VARCHAR2);
PROCEDURE set_vpd_context(
p_authorization IN VARCHAR2,
p_probe_id IN VARCHAR2 DEFAULT NULL
);
FUNCTION set_vpd_context_sql(p_authorization IN VARCHAR2) RETURN NUMBER;
PROCEDURE clear_vpd_context;
END;
@@ -38,12 +41,19 @@ CREATE OR REPLACE PACKAGE BODY cb_ords_handler_pkg AS
RETURN TRIM(SUBSTR(v_auth, 8));
END;
PROCEDURE set_vpd_context(p_authorization IN VARCHAR2) AS
PROCEDURE set_vpd_context(
p_authorization IN VARCHAR2,
p_probe_id IN VARCHAR2 DEFAULT NULL
) AS
v_bearer_key VARCHAR2(4000);
BEGIN
DBMS_SESSION.CLEAR_IDENTIFIER;
admin.cb_agent_ctx_pkg.clear_user;
v_bearer_key := extract_bearer_key(p_authorization);
admin.cb_agent_ctx_pkg.set_user_by_bearer(v_bearer_key);
IF TRIM(p_probe_id) IS NOT NULL THEN
DBMS_SESSION.SET_IDENTIFIER(SUBSTR(TRIM(p_probe_id), 1, 64));
END IF;
END;
FUNCTION set_vpd_context_sql(p_authorization IN VARCHAR2) RETURN NUMBER AS
@@ -55,6 +65,7 @@ CREATE OR REPLACE PACKAGE BODY cb_ords_handler_pkg AS
PROCEDURE clear_vpd_context AS
BEGIN
admin.cb_agent_ctx_pkg.clear_user;
DBMS_SESSION.CLEAR_IDENTIFIER;
END;
END;
/
@@ -93,7 +104,7 @@ DECLARE
v_vpd_predicate VARCHAR2(32767);
v_effective_sql VARCHAR2(32767);
BEGIN
cb_ords_handler_pkg.set_vpd_context(:auth_header);
cb_ords_handler_pkg.set_vpd_context(:auth_header, :probe_id);
-- The predicate below is the value returned by the same DBMS_RLS policy
-- function that protects ADMIN.CB_V_SEARCH_DOCUMENTS.
@@ -156,6 +167,16 @@ END;
p_param_type => 'STRING',
p_access_method => 'IN'
);
ORDS.DEFINE_PARAMETER(
p_module_name => 'cb.agent.security',
p_pattern => 'vpd/documents',
p_method => 'POST',
p_name => 'X-VPD-Probe-Id',
p_bind_variable_name => 'probe_id',
p_source_type => 'HEADER',
p_param_type => 'STRING',
p_access_method => 'IN'
);
ORDS.DEFINE_PARAMETER(
p_module_name => 'cb.agent.security',
p_pattern => 'vpd/documents',

View File

@@ -53,7 +53,7 @@ DECLARE
v_vpd_predicate VARCHAR2(32767);
v_effective_sql VARCHAR2(32767);
BEGIN
cb_ords_handler_pkg.set_vpd_context(:auth_header);
cb_ords_handler_pkg.set_vpd_context(:auth_header, :probe_id);
BEGIN
v_vpd_predicate := admin.cb_agent_doc_vpd_filter('ADMIN', 'CB_VECTOR_SEARCH_DOCUMENTS');
@@ -163,6 +163,17 @@ END;
p_access_method => 'IN'
);
ORDS.DEFINE_PARAMETER(
p_module_name => 'cb.agent.vector',
p_pattern => 'search',
p_method => 'POST',
p_name => 'X-VPD-Probe-Id',
p_bind_variable_name => 'probe_id',
p_source_type => 'HEADER',
p_param_type => 'STRING',
p_access_method => 'IN'
);
ORDS.DEFINE_PARAMETER(
p_module_name => 'cb.agent.vector',
p_pattern => 'search',

View File

@@ -0,0 +1,70 @@
-- ============================================================
-- 42_agent_ords_fga_execution_audit.sql
-- Durable, request-correlated execution evidence for VPD probes.
--
-- Run as the protected-object owner (ADMIN in this PoC), after the
-- VPD policies and CB_PROTECTED_OBJECT entries have been applied.
--
-- Each enabled protected object gets an FGA SELECT policy. Autonomous Oracle
-- writes SQL_TEXT and RLS_INFO to UNIFIED_AUDIT_TRAIL (traditional databases
-- can expose the same information through DBA_FGA_AUDIT_TRAIL). The ORDS handler puts the
-- backoffice-generated X-VPD-Probe-Id into CLIENT_ID, so the UI can read
-- exactly this request's audit row rather than guess from V$SQL.
-- ============================================================
WHENEVER SQLERROR EXIT SQL.SQLCODE
SET ECHO ON
SET FEEDBACK ON
PROMPT === Applying FGA execution-audit policies ===
DECLARE
v_policy_name VARCHAR2(128);
BEGIN
FOR r IN (
SELECT object_id, owner, object_name
FROM cb_protected_object
WHERE enabled_yn = 'Y'
ORDER BY object_id
) LOOP
IF UPPER(r.owner) <> USER THEN
RAISE_APPLICATION_ERROR(
-20842,
'Run this script as protected object owner ' || r.owner
|| ' (current user: ' || USER || ')'
);
END IF;
v_policy_name := 'CB_VPD_EXEC_AUDIT_' || r.object_id;
BEGIN
DBMS_FGA.DROP_POLICY(
object_schema => r.owner,
object_name => r.object_name,
policy_name => v_policy_name
);
EXCEPTION
WHEN OTHERS THEN
-- ORA-28102: policy does not exist. Other errors must stop setup.
IF SQLCODE <> -28102 THEN
RAISE;
END IF;
END;
DBMS_FGA.ADD_POLICY(
object_schema => r.owner,
object_name => r.object_name,
policy_name => v_policy_name,
audit_condition => NULL,
audit_column => NULL,
statement_types => 'SELECT',
audit_trail => DBMS_FGA.DB + DBMS_FGA.EXTENDED,
enable => TRUE
);
END LOOP;
END;
/
COMMIT;
PROMPT === FGA policies are ready ===
PROMPT Run 22, 29 and 43 as CB_ORDS, then run a new permission-result probe.
PROMPT The resulting row is read from UNIFIED_AUDIT_TRAIL by CLIENT_IDENTIFIER.
EXIT;

View File

@@ -0,0 +1,59 @@
-- ============================================================
-- 43_agent_ords_probe_id_handler_patch.sql
-- Adds X-VPD-Probe-Id to existing generic cb.object.query handlers.
--
-- Run as CB_ORDS after 22_agent_ords_security_ords_handler_setup.sql.
-- The dedicated document/vector handlers are updated by 22/29 themselves.
-- ============================================================
WHENEVER SQLERROR EXIT SQL.SQLCODE
SET ECHO ON
SET FEEDBACK ON
PROMPT === Patching generic object-query handlers for FGA correlation ===
DECLARE
v_source CLOB;
BEGIN
FOR r IN (
SELECT m.name AS module_name,
t.uri_template,
h.method,
h.source
FROM user_ords_handlers h
JOIN user_ords_templates t ON t.id = h.template_id
JOIN user_ords_modules m ON m.id = t.module_id
WHERE m.name = 'cb.object.query'
AND h.method = 'POST'
AND INSTR(h.source, 'cb_ords_handler_pkg.set_vpd_context(:auth_header)') > 0
) LOOP
v_source := REPLACE(
r.source,
'cb_ords_handler_pkg.set_vpd_context(:auth_header)',
'cb_ords_handler_pkg.set_vpd_context(:auth_header, :probe_id)'
);
ORDS.DEFINE_HANDLER(
p_module_name => r.module_name,
p_pattern => r.uri_template,
p_method => r.method,
p_source_type => ORDS.source_type_plsql,
p_source => v_source,
p_items_per_page => 0
);
ORDS.DEFINE_PARAMETER(
p_module_name => r.module_name,
p_pattern => r.uri_template,
p_method => r.method,
p_name => 'X-VPD-Probe-Id',
p_bind_variable_name => 'probe_id',
p_source_type => 'HEADER',
p_param_type => 'STRING',
p_access_method => 'IN'
);
END LOOP;
END;
/
COMMIT;
PROMPT === Generic handler patch complete ===
EXIT;