-- ============================================================ -- 47_dds_ad_identity_test_setup.sql -- -- Test-only bridge for the isolated dds.test Active Directory domain. -- Maps immutable AD objectGUID values to the existing HMM application users -- 1 and 2, then publishes only their passwordless local DDS END USERs. -- -- This does NOT validate an AD/OIDC JWT. A verified issuer + subject must be -- resolved by the MCP application before it uses this bridge. -- ============================================================ WHENEVER SQLERROR EXIT SQL.SQLCODE SET ECHO OFF SET FEEDBACK ON SET DEFINE OFF PROMPT === 1. Creating external identity bridge === BEGIN EXECUTE IMMEDIATE q'[ CREATE TABLE cb_external_identity_binding ( issuer VARCHAR2(512) NOT NULL, subject VARCHAR2(512) NOT NULL, application_user_id NUMBER NOT NULL, display_name VARCHAR2(256), active CHAR(1) DEFAULT 'Y' NOT NULL CHECK (active IN ('Y', 'N')), created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL, updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL, CONSTRAINT cb_external_identity_binding_pk PRIMARY KEY (issuer, subject) )]'; EXCEPTION WHEN OTHERS THEN IF SQLCODE <> -955 THEN RAISE; END IF; END; / BEGIN EXECUTE IMMEDIATE 'CREATE INDEX cb_external_identity_binding_user_ix ' || 'ON cb_external_identity_binding (application_user_id)'; EXCEPTION WHEN OTHERS THEN IF SQLCODE <> -955 THEN RAISE; END IF; END; / PROMPT === 2. Creating DDS END USER map === BEGIN EXECUTE IMMEDIATE q'[ CREATE TABLE cb_dds_end_user_map ( application_user_id NUMBER PRIMARY KEY, end_user_name VARCHAR2(128) NOT NULL UNIQUE, data_role_name VARCHAR2(128) NOT NULL UNIQUE, lookup_key_ref VARCHAR2(128) NOT NULL, grant_name VARCHAR2(128) NOT NULL, publish_status VARCHAR2(20) NOT NULL CHECK (publish_status IN ('PENDING', 'PUBLISHED', 'REVOKED', 'FAILED')), published_at TIMESTAMP, last_error VARCHAR2(1000) )]'; EXCEPTION WHEN OTHERS THEN IF SQLCODE <> -955 THEN RAISE; END IF; END; / DECLARE v_active_users NUMBER; BEGIN SELECT COUNT(*) INTO v_active_users FROM cb_app_user WHERE user_id IN (1, 2) AND active = 'Y'; IF v_active_users <> 2 THEN RAISE_APPLICATION_ERROR(-20947, 'Expected active HMM application users 1 and 2.'); END IF; END; / PROMPT === 3. Binding dds.test immutable subjects to HMM users === MERGE INTO cb_external_identity_binding target USING ( SELECT 'urn:dds-ad:test' AS issuer, 'fa7ebe4b-aca8-4049-a436-7f3da2d27a9f' AS subject, 1 AS application_user_id, 'dds-alice' AS display_name FROM dual UNION ALL SELECT 'urn:dds-ad:test', '128546cf-ec0a-4e99-8f51-dfce29280c91', 2, 'dds-bob' FROM dual ) source ON (target.issuer = source.issuer AND target.subject = source.subject) WHEN MATCHED THEN UPDATE SET target.application_user_id = source.application_user_id, target.display_name = source.display_name, target.active = 'Y', target.updated_at = SYSTIMESTAMP WHEN NOT MATCHED THEN INSERT ( issuer, subject, application_user_id, display_name, active ) VALUES ( source.issuer, source.subject, source.application_user_id, source.display_name, 'Y' ); MERGE INTO cb_dds_end_user_map target USING ( SELECT user_id AS application_user_id, 'DDS_U_' || TO_CHAR(user_id) AS end_user_name, 'DDS_U_' || TO_CHAR(user_id) || '_ROLE' AS data_role_name, 'DDS_OCI_IAM_CLIENT_SECRET_DERIVED_V1' AS lookup_key_ref, 'DDS_MCP_U_' || TO_CHAR(user_id) || '_VECTOR_GRANT' AS grant_name FROM cb_app_user WHERE user_id IN (1, 2) ) source ON (target.application_user_id = source.application_user_id) WHEN MATCHED THEN UPDATE SET target.end_user_name = source.end_user_name, target.data_role_name = source.data_role_name, target.lookup_key_ref = source.lookup_key_ref, target.grant_name = source.grant_name, target.publish_status = 'PENDING', target.last_error = NULL WHEN NOT MATCHED THEN INSERT ( application_user_id, end_user_name, data_role_name, lookup_key_ref, grant_name, publish_status ) VALUES ( source.application_user_id, source.end_user_name, source.data_role_name, source.lookup_key_ref, source.grant_name, 'PENDING' ); PROMPT === 4. Publishing DDS identities only (default deny until data grants exist) === BEGIN FOR mapped_user IN ( SELECT application_user_id, end_user_name, data_role_name FROM cb_dds_end_user_map WHERE application_user_id IN (1, 2) ORDER BY application_user_id ) LOOP EXECUTE IMMEDIATE 'CREATE END USER IF NOT EXISTS "' || mapped_user.end_user_name || '"'; EXECUTE IMMEDIATE 'CREATE DATA ROLE IF NOT EXISTS ' || mapped_user.data_role_name; EXECUTE IMMEDIATE 'GRANT DATA ROLE ' || mapped_user.data_role_name || ' TO "' || mapped_user.end_user_name || '"'; UPDATE cb_dds_end_user_map SET publish_status = 'PUBLISHED', published_at = SYSTIMESTAMP, last_error = NULL WHERE application_user_id = mapped_user.application_user_id; END LOOP; COMMIT; END; / PROMPT === 5. Identity bridge inventory === SELECT b.issuer, b.subject, b.display_name, b.application_user_id, m.end_user_name, m.data_role_name, m.publish_status FROM cb_external_identity_binding b JOIN cb_dds_end_user_map m ON m.application_user_id = b.application_user_id WHERE b.issuer = 'urn:dds-ad:test' ORDER BY b.application_user_id; PROMPT === AD identity to DDS END USER test setup complete === EXIT;