-- ============================================================ -- 84_hmm_carrier_team_vpd.sql -- -- Row security for HMM_CARRIER_ASSIGNMENTS_V: -- HMM_HR_VIEWER -> current employee only -- HMM_HR_MANAGER -> current employee and direct reports -- HMM_HR_ADMIN -> all assignments -- -- Run as ADMIN after 72_hmm_leave_team_vpd.sql and -- 81_hmm_carrier_access_groups.sql. Plain bearer tokens are -- never stored by this script. -- ============================================================ WHENEVER SQLERROR EXIT SQL.SQLCODE SET ECHO OFF SET FEEDBACK ON SET DEFINE OFF PROMPT === 1. Registering the protected carrier object === DECLARE v_object_id NUMBER; BEGIN BEGIN SELECT object_id INTO v_object_id FROM hmm_access_objects WHERE owner = 'ADMIN' AND object_name = 'HMM_CARRIER_ASSIGNMENTS_V'; UPDATE hmm_access_objects SET enabled_yn = 'Y', description = 'Employee-to-carrier assignments protected by employee hierarchy', ords_path = 'cb-ords/cb-object-query/admin/hmm_carrier_assignments_v' WHERE object_id = v_object_id; EXCEPTION WHEN NO_DATA_FOUND THEN SELECT NVL(MAX(object_id), 0) + 1 INTO v_object_id FROM hmm_access_objects; INSERT INTO hmm_access_objects ( object_id, owner, object_name, ords_path, enabled_yn, description ) VALUES ( v_object_id, 'ADMIN', 'HMM_CARRIER_ASSIGNMENTS_V', 'cb-ords/cb-object-query/admin/hmm_carrier_assignments_v', 'Y', 'Employee-to-carrier assignments protected by employee hierarchy' ); END; FOR c IN ( SELECT column_name FROM user_tab_columns WHERE table_name = 'HMM_CARRIER_ASSIGNMENTS_V' ORDER BY column_id ) LOOP MERGE INTO hmm_access_object_columns dst USING ( SELECT v_object_id object_id, c.column_name column_name FROM dual ) src ON (dst.object_id = src.object_id AND dst.column_name = src.column_name) WHEN NOT MATCHED THEN INSERT ( column_id, object_id, column_name, sensitive_yn, sensitivity_level, redaction_method ) VALUES ( (SELECT NVL(MAX(column_id), 0) + 1 FROM hmm_access_object_columns), src.object_id, src.column_name, 'N', 'PUBLIC', 'NONE' ); END LOOP; END; / PROMPT === 2. Registering role rules === DECLARE PROCEDURE ensure_permission( p_role_name IN VARCHAR2, p_rule_type IN VARCHAR2 ) AS v_role_id NUMBER; v_perm_id NUMBER; BEGIN SELECT role_id INTO v_role_id FROM hmm_access_roles WHERE role_name = p_role_name AND active_yn = 'Y'; BEGIN SELECT perm_id INTO v_perm_id FROM hmm_access_permissions WHERE role_id = v_role_id AND target_name = 'HMM_CARRIER_ASSIGNMENTS_V' AND action_name = 'SELECT'; UPDATE hmm_access_permissions SET permission_effect = 'ALLOW' WHERE perm_id = v_perm_id; EXCEPTION WHEN NO_DATA_FOUND THEN SELECT cb_permission_seq.NEXTVAL INTO v_perm_id FROM dual; INSERT INTO hmm_access_permissions ( perm_id, role_id, target_name, action_name, permission_effect ) VALUES ( v_perm_id, v_role_id, 'HMM_CARRIER_ASSIGNMENTS_V', 'SELECT', 'ALLOW' ); END; DELETE FROM hmm_access_permission_rules WHERE perm_id = v_perm_id; INSERT INTO hmm_access_permission_rules ( rule_id, perm_id, rule_column, rule_type, rule_value ) VALUES ( cb_permission_rule_seq.NEXTVAL, v_perm_id, 'EMPLOYEE_ID', p_rule_type, NULL ); END; BEGIN ensure_permission('HMM_HR_VIEWER', 'SELF'); ensure_permission('HMM_HR_MANAGER', 'MANAGED_TEAM'); ensure_permission('HMM_HR_ADMIN', 'ALL'); END; / COMMIT; PROMPT === 3. Creating the carrier VPD predicate === CREATE OR REPLACE FUNCTION hmm_carrier_vpd_filter( p_schema IN VARCHAR2, p_object IN VARCHAR2 ) RETURN VARCHAR2 AUTHID DEFINER AS v_employee_id NUMBER; v_all_rule NUMBER := 0; v_team_rule NUMBER := 0; v_self_rule NUMBER := 0; BEGIN IF UPPER(TRIM(p_schema)) != 'ADMIN' OR UPPER(TRIM(p_object)) != 'HMM_CARRIER_ASSIGNMENTS_V' THEN RETURN '1 = 0'; END IF; BEGIN v_employee_id := TO_NUMBER( SYS_CONTEXT('HMM_ACCESS_CTX', 'EMPLOYEE_ID') ); EXCEPTION WHEN OTHERS THEN RETURN '1 = 0'; END; IF v_employee_id IS NULL THEN RETURN '1 = 0'; END IF; SELECT NVL(MAX(CASE WHEN rule.rule_type = 'ALL' THEN 1 ELSE 0 END), 0), NVL(MAX(CASE WHEN rule.rule_type = 'MANAGED_TEAM' THEN 1 ELSE 0 END), 0), NVL(MAX(CASE WHEN rule.rule_type = 'SELF' THEN 1 ELSE 0 END), 0) INTO v_all_rule, v_team_rule, v_self_rule FROM ( SELECT employee_role.role_id FROM hmm_employee_access_roles employee_role WHERE employee_role.employee_id = v_employee_id UNION SELECT group_role.role_id FROM hmm_access_group_members group_member JOIN hmm_access_groups access_group ON access_group.group_id = group_member.group_id AND access_group.active_yn = 'Y' JOIN hmm_group_access_roles group_role ON group_role.group_id = group_member.group_id WHERE group_member.employee_id = v_employee_id ) effective_role JOIN hmm_access_roles role ON role.role_id = effective_role.role_id AND role.active_yn = 'Y' JOIN hmm_access_permissions permission ON permission.role_id = role.role_id AND permission.target_name = 'HMM_CARRIER_ASSIGNMENTS_V' AND permission.action_name = 'SELECT' AND permission.permission_effect = 'ALLOW' JOIN hmm_access_permission_rules rule ON rule.perm_id = permission.perm_id AND UPPER(TRIM(rule.rule_column)) = 'EMPLOYEE_ID'; IF v_all_rule = 1 THEN RETURN '1 = 1'; END IF; IF v_team_rule = 1 THEN RETURN 'EMPLOYEE_ID IN (' || 'SELECT employee.employee_id ' || 'FROM ADMIN.HMM_HR_EMPLOYEES employee ' || 'WHERE employee.employee_id = ' || 'TO_NUMBER(SYS_CONTEXT(''HMM_ACCESS_CTX'', ''EMPLOYEE_ID'')) ' || 'OR employee.manager_employee_id = ' || 'TO_NUMBER(SYS_CONTEXT(''HMM_ACCESS_CTX'', ''EMPLOYEE_ID''))' || ')'; END IF; IF v_self_rule = 1 THEN RETURN 'EMPLOYEE_ID = TO_NUMBER(' || 'SYS_CONTEXT(''HMM_ACCESS_CTX'', ''EMPLOYEE_ID''))'; END IF; RETURN '1 = 0'; EXCEPTION WHEN OTHERS THEN RETURN '1 = 0'; END; / SHOW ERRORS FUNCTION hmm_carrier_vpd_filter PROMPT === 4. Attaching the VPD policy === BEGIN BEGIN DBMS_RLS.DROP_POLICY( object_schema => 'ADMIN', object_name => 'HMM_CARRIER_ASSIGNMENTS_V', policy_name => 'HMM_CARRIER_SCOPE_POLICY' ); EXCEPTION WHEN OTHERS THEN IF SQLCODE != -28102 THEN RAISE; END IF; END; DBMS_RLS.ADD_POLICY( object_schema => 'ADMIN', object_name => 'HMM_CARRIER_ASSIGNMENTS_V', policy_name => 'HMM_CARRIER_SCOPE_POLICY', function_schema => 'ADMIN', policy_function => 'HMM_CARRIER_VPD_FILTER', statement_types => 'SELECT', update_check => FALSE, enable => TRUE, policy_type => DBMS_RLS.CONTEXT_SENSITIVE ); END; / PROMPT === 5. Granting the non-exempt runtime read boundary === GRANT SELECT ON hmm_carrier_assignments_v TO cb_ords; GRANT SELECT ON hmm_rds_carriers_v TO cb_ords; GRANT SELECT ON hmm_rds_carrier_perf_v TO cb_ords; GRANT SELECT ON hmm_rds_carrier_latest_v TO cb_ords; CREATE OR REPLACE SYNONYM cb_ords.hmm_carrier_assignments_v FOR admin.hmm_carrier_assignments_v; CREATE OR REPLACE SYNONYM cb_ords.hmm_rds_carriers_v FOR admin.hmm_rds_carriers_v; CREATE OR REPLACE SYNONYM cb_ords.hmm_rds_carrier_perf_v FOR admin.hmm_rds_carrier_perf_v; CREATE OR REPLACE SYNONYM cb_ords.hmm_rds_carrier_latest_v FOR admin.hmm_rds_carrier_latest_v; PROMPT === 6. Recording policy notes === MERGE INTO hmm_access_vpd_filter_notes dst USING ( SELECT 'ADMIN' function_owner, 'HMM_CARRIER_VPD_FILTER' function_name, 'Filters carrier assignments by the authenticated employee role and employee hierarchy.' description FROM dual ) src ON (dst.function_owner = src.function_owner AND dst.function_name = src.function_name) WHEN MATCHED THEN UPDATE SET dst.description = src.description, dst.updated_at = SYSTIMESTAMP WHEN NOT MATCHED THEN INSERT ( function_owner, function_name, description, updated_at ) VALUES ( src.function_owner, src.function_name, src.description, SYSTIMESTAMP ); MERGE INTO hmm_access_vpd_policy_notes dst USING ( SELECT 'ADMIN' object_owner, 'HMM_CARRIER_ASSIGNMENTS_V' object_name, 'HMM_CARRIER_SCOPE_POLICY' policy_name, 'Restricts carrier assignments to self, direct reports, or explicit HR administrator access.' description FROM dual ) src ON ( dst.object_owner = src.object_owner AND dst.object_name = src.object_name AND dst.policy_name = src.policy_name ) WHEN MATCHED THEN UPDATE SET dst.description = src.description, dst.updated_at = SYSTIMESTAMP WHEN NOT MATCHED THEN INSERT ( object_owner, object_name, policy_name, description, updated_at ) VALUES ( src.object_owner, src.object_name, src.policy_name, src.description, SYSTIMESTAMP ); COMMIT; PROMPT === 7. Verification inventory === SELECT object_name, policy_name, function, sel, enable, policy_type FROM all_policies WHERE object_owner = 'ADMIN' AND object_name = 'HMM_CARRIER_ASSIGNMENTS_V' AND policy_name = 'HMM_CARRIER_SCOPE_POLICY'; SELECT role.role_name, permission.target_name, rule.rule_column, rule.rule_type FROM hmm_access_permissions permission JOIN hmm_access_roles role ON role.role_id = permission.role_id JOIN hmm_access_permission_rules rule ON rule.perm_id = permission.perm_id WHERE permission.target_name = 'HMM_CARRIER_ASSIGNMENTS_V' ORDER BY role.role_name; PROMPT === HMM carrier team VPD ready ===