[Developer] #619 map stakeholder tokens to permission rules
This commit is contained in:
@@ -46,6 +46,7 @@ CREATE TABLE cb_app_user (
|
||||
user_name VARCHAR2(50) NOT NULL,
|
||||
employee_no VARCHAR2(20) NOT NULL,
|
||||
dept_code VARCHAR2(20) NOT NULL,
|
||||
stakeholder_user_id VARCHAR2(30),
|
||||
can_read_contents CHAR(1) DEFAULT 'N' CHECK (can_read_contents IN ('Y','N')) NOT NULL,
|
||||
active CHAR(1) DEFAULT 'Y' CHECK (active IN ('Y','N')) NOT NULL
|
||||
);
|
||||
@@ -87,6 +88,7 @@ CREATE TABLE cb_permission_column (
|
||||
CREATE TABLE cb_agent_bearer_key (
|
||||
key_id NUMBER PRIMARY KEY,
|
||||
user_id NUMBER NOT NULL REFERENCES cb_app_user(user_id),
|
||||
stakeholder_user_id VARCHAR2(30),
|
||||
key_hash VARCHAR2(128) NOT NULL UNIQUE,
|
||||
key_prefix VARCHAR2(16),
|
||||
issued_at DATE DEFAULT SYSDATE NOT NULL,
|
||||
@@ -96,9 +98,9 @@ CREATE TABLE cb_agent_bearer_key (
|
||||
);
|
||||
|
||||
PROMPT === 3. Seeding permissions ===
|
||||
INSERT INTO cb_app_user VALUES (101, '이에이치알', 'E10234', 'HR', 'N', 'Y');
|
||||
INSERT INTO cb_app_user VALUES (102, '박파이넨스', 'E2001', 'FIN', 'N', 'Y');
|
||||
INSERT INTO cb_app_user VALUES (103, '김어드민', 'E99999', 'HQ', 'Y', 'Y');
|
||||
INSERT INTO cb_app_user VALUES (101, '이에이치알', 'E10234', 'HR', NULL, 'N', 'Y');
|
||||
INSERT INTO cb_app_user VALUES (102, '박파이넨스', 'E2001', 'FIN', NULL, 'N', 'Y');
|
||||
INSERT INTO cb_app_user VALUES (103, '김어드민', 'E99999', 'HQ', NULL, 'Y', 'Y');
|
||||
|
||||
INSERT INTO cb_app_role VALUES (10, 'HR_DEPT_ROLE', 'INTERNAL');
|
||||
INSERT INTO cb_app_role VALUES (20, 'FIN_SELF_ROLE', 'INTERNAL');
|
||||
|
||||
@@ -169,6 +169,58 @@ BEGIN
|
||||
quote_literal('(^|,)' || UPPER(TRIM(r.rule_value)) || '(,|$)') || ')'
|
||||
);
|
||||
END IF;
|
||||
ELSIF r.rule_type IN ('STAKEHOLDER_SELF', 'STAKEHOLDER_CHANNEL') THEN
|
||||
-- 업무 사용자 원장(KB_STAKEHOLDERS)에서 해석한 토큰 주체를 쓴다.
|
||||
-- CUST_ID/CONTRACT_NO는 계약원장을 한 단계 감싼 EXISTS로만 연결해
|
||||
-- 임의 SQL이나 외부 rule text가 predicate에 섞이지 않게 한다.
|
||||
v_column := safe_column(p_schema, p_object, r.rule_column);
|
||||
IF v_column IS NOT NULL
|
||||
AND UPPER(p_schema) = 'POC_2' THEN
|
||||
IF r.rule_type = 'STAKEHOLDER_SELF'
|
||||
AND ((v_target = 'KB_CONTRACTS' AND v_column = 'FC_ID')
|
||||
OR (v_target = 'KB_STAKEHOLDERS' AND v_column = 'USER_ID')) THEN
|
||||
append_or(
|
||||
r.permission_effect,
|
||||
v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_USER_ID'')'
|
||||
);
|
||||
ELSIF r.rule_type = 'STAKEHOLDER_CHANNEL'
|
||||
AND v_target = 'KB_CONTRACTS'
|
||||
AND v_column = 'FC_CHANNEL' THEN
|
||||
append_or(
|
||||
r.permission_effect,
|
||||
v_column || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_CHANNEL'')'
|
||||
);
|
||||
ELSIF v_target IN ('KB_CUSTOMERS', 'KB_COVERAGES', 'KB_CLAIMS', 'KB_EXTERNAL_HOLDINGS')
|
||||
AND v_column IN ('CUST_ID', 'CONTRACT_NO') THEN
|
||||
DECLARE
|
||||
v_contract_key VARCHAR2(30);
|
||||
v_context_key VARCHAR2(30);
|
||||
v_context_name VARCHAR2(30);
|
||||
BEGIN
|
||||
v_contract_key := CASE v_column
|
||||
WHEN 'CUST_ID' THEN 'CUST_ID'
|
||||
WHEN 'CONTRACT_NO' THEN 'CONTRACT_NO'
|
||||
END;
|
||||
v_context_key := CASE r.rule_type
|
||||
WHEN 'STAKEHOLDER_SELF' THEN 'FC_ID'
|
||||
ELSE 'FC_CHANNEL'
|
||||
END;
|
||||
v_context_name := CASE r.rule_type
|
||||
WHEN 'STAKEHOLDER_SELF' THEN 'STAKEHOLDER_USER_ID'
|
||||
ELSE 'STAKEHOLDER_CHANNEL'
|
||||
END;
|
||||
append_or(
|
||||
r.permission_effect,
|
||||
'EXISTS (SELECT 1 FROM (' ||
|
||||
'SELECT c.' || v_contract_key || ' AS access_key ' ||
|
||||
'FROM POC_2.KB_CONTRACTS c ' ||
|
||||
'WHERE c.' || v_context_key || ' = SYS_CONTEXT(''CB_AGENT_CTX'', ''' ||
|
||||
v_context_name || ''')) allowed_contract ' ||
|
||||
'WHERE allowed_contract.access_key = ' || v_column || ')'
|
||||
);
|
||||
END;
|
||||
END IF;
|
||||
END IF;
|
||||
ELSIF r.rule_type = '=' THEN
|
||||
v_column := safe_column(p_schema, p_object, r.rule_column);
|
||||
IF v_column IS NOT NULL THEN
|
||||
|
||||
533
sql/adb/46_kb_stakeholder_token_permission_example.sql
Normal file
533
sql/adb/46_kb_stakeholder_token_permission_example.sql
Normal file
@@ -0,0 +1,533 @@
|
||||
-- ============================================================
|
||||
-- 46_kb_stakeholder_token_permission_example.sql
|
||||
--
|
||||
-- KB_STAKEHOLDERS를 토큰의 업무 주체로 연결하고, 접근 규칙 화면에서
|
||||
-- 관리하는 설계사/지점장 예제 권한을 등록한다.
|
||||
--
|
||||
-- Prerequisite: 17, 25, 26 scripts. Execute as ADMIN.
|
||||
-- 26 must include STAKEHOLDER_SELF / STAKEHOLDER_CHANNEL rule support.
|
||||
-- ============================================================
|
||||
WHENEVER SQLERROR EXIT SQL.SQLCODE
|
||||
SET ECHO OFF
|
||||
SET FEEDBACK ON
|
||||
SET DEFINE OFF
|
||||
|
||||
PROMPT === 1. Adding stakeholder bridge columns ===
|
||||
DECLARE
|
||||
PROCEDURE add_column_if_missing(
|
||||
p_table_name IN VARCHAR2,
|
||||
p_column_name IN VARCHAR2,
|
||||
p_ddl IN VARCHAR2
|
||||
) IS
|
||||
v_count NUMBER;
|
||||
BEGIN
|
||||
SELECT COUNT(*)
|
||||
INTO v_count
|
||||
FROM user_tab_columns
|
||||
WHERE table_name = p_table_name
|
||||
AND column_name = p_column_name;
|
||||
|
||||
IF v_count = 0 THEN
|
||||
EXECUTE IMMEDIATE p_ddl;
|
||||
END IF;
|
||||
END;
|
||||
BEGIN
|
||||
add_column_if_missing(
|
||||
'CB_APP_USER',
|
||||
'STAKEHOLDER_USER_ID',
|
||||
'ALTER TABLE cb_app_user ADD (stakeholder_user_id VARCHAR2(30))'
|
||||
);
|
||||
add_column_if_missing(
|
||||
'CB_AGENT_BEARER_KEY',
|
||||
'STAKEHOLDER_USER_ID',
|
||||
'ALTER TABLE cb_agent_bearer_key ADD (stakeholder_user_id VARCHAR2(30))'
|
||||
);
|
||||
END;
|
||||
/
|
||||
|
||||
PROMPT === 2. Resolving Bearer Token to stakeholder context ===
|
||||
CREATE OR REPLACE PACKAGE cb_agent_ctx_pkg AUTHID DEFINER AS
|
||||
PROCEDURE clear_user;
|
||||
PROCEDURE set_user(p_user_id IN NUMBER);
|
||||
PROCEDURE set_user_values(
|
||||
p_user_id IN NUMBER,
|
||||
p_emp_no IN VARCHAR2,
|
||||
p_dept_code IN VARCHAR2,
|
||||
p_can_read_contents IN VARCHAR2
|
||||
);
|
||||
PROCEDURE set_user_by_bearer(p_bearer_key IN VARCHAR2);
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE PACKAGE BODY cb_agent_ctx_pkg AS
|
||||
PROCEDURE clear_stakeholder_context AS
|
||||
BEGIN
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_USER_ID', NULL);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_ROLE', NULL);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_CHANNEL', NULL);
|
||||
END;
|
||||
|
||||
PROCEDURE clear_user AS
|
||||
BEGIN
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'USER_ID', NULL);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'EMP_NO', NULL);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'DEPT_CODE', NULL);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'CAN_READ_CONTENTS', NULL);
|
||||
clear_stakeholder_context;
|
||||
END;
|
||||
|
||||
PROCEDURE set_user_values(
|
||||
p_user_id IN NUMBER,
|
||||
p_emp_no IN VARCHAR2,
|
||||
p_dept_code IN VARCHAR2,
|
||||
p_can_read_contents IN VARCHAR2
|
||||
) AS
|
||||
BEGIN
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'USER_ID', TO_CHAR(p_user_id));
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'EMP_NO', p_emp_no);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'DEPT_CODE', p_dept_code);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'CAN_READ_CONTENTS', p_can_read_contents);
|
||||
clear_stakeholder_context;
|
||||
END;
|
||||
|
||||
PROCEDURE set_stakeholder_context(
|
||||
p_stakeholder_user_id IN VARCHAR2,
|
||||
p_role IN VARCHAR2,
|
||||
p_channel IN VARCHAR2
|
||||
) AS
|
||||
v_channel VARCHAR2(50);
|
||||
BEGIN
|
||||
v_channel := CASE TRIM(p_channel)
|
||||
WHEN '설계사채널' THEN '설계사'
|
||||
WHEN 'GA채널' THEN 'GA'
|
||||
ELSE TRIM(p_channel)
|
||||
END;
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_USER_ID', p_stakeholder_user_id);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_ROLE', p_role);
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_CHANNEL', v_channel);
|
||||
END;
|
||||
|
||||
PROCEDURE set_user(p_user_id IN NUMBER) AS
|
||||
v_emp_no cb_app_user.employee_no%TYPE;
|
||||
v_dept_code cb_app_user.dept_code%TYPE;
|
||||
v_can_read_contents cb_app_user.can_read_contents%TYPE;
|
||||
BEGIN
|
||||
SELECT employee_no,
|
||||
dept_code,
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM cb_user_role ur
|
||||
JOIN cb_permission p ON p.role_id = ur.role_id
|
||||
JOIN cb_permission_column pc ON pc.permission_id = p.perm_id
|
||||
WHERE ur.user_id = p_user_id
|
||||
AND p.target_name = 'CB_V_SEARCH_DOCUMENTS'
|
||||
AND p.action_name = 'SELECT'
|
||||
AND pc.column_name = 'CONTENTS'
|
||||
) THEN 'Y'
|
||||
ELSE 'N'
|
||||
END
|
||||
INTO v_emp_no, v_dept_code, v_can_read_contents
|
||||
FROM cb_app_user
|
||||
WHERE user_id = p_user_id
|
||||
AND active = 'Y';
|
||||
|
||||
set_user_values(p_user_id, v_emp_no, v_dept_code, v_can_read_contents);
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
clear_user;
|
||||
RAISE_APPLICATION_ERROR(-20003, 'Mapped application user not found');
|
||||
END;
|
||||
|
||||
PROCEDURE set_user_by_bearer(p_bearer_key IN VARCHAR2) AS
|
||||
v_user_id cb_app_user.user_id%TYPE;
|
||||
v_emp_no cb_app_user.employee_no%TYPE;
|
||||
v_dept_code cb_app_user.dept_code%TYPE;
|
||||
v_can_read_contents cb_app_user.can_read_contents%TYPE;
|
||||
v_stakeholder_user_id VARCHAR2(30);
|
||||
v_stakeholder_role VARCHAR2(50);
|
||||
v_stakeholder_channel VARCHAR2(50);
|
||||
BEGIN
|
||||
IF p_bearer_key IS NULL THEN
|
||||
clear_user;
|
||||
RAISE_APPLICATION_ERROR(-20001, 'Authorization Bearer key is required');
|
||||
END IF;
|
||||
|
||||
SELECT u.user_id,
|
||||
u.employee_no,
|
||||
u.dept_code,
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM cb_user_role ur
|
||||
JOIN cb_permission p ON p.role_id = ur.role_id
|
||||
JOIN cb_permission_column pc ON pc.permission_id = p.perm_id
|
||||
WHERE ur.user_id = u.user_id
|
||||
AND p.target_name = 'CB_V_SEARCH_DOCUMENTS'
|
||||
AND p.action_name = 'SELECT'
|
||||
AND pc.column_name = 'CONTENTS'
|
||||
) THEN 'Y'
|
||||
ELSE 'N'
|
||||
END,
|
||||
COALESCE(k.stakeholder_user_id, u.stakeholder_user_id)
|
||||
INTO v_user_id, v_emp_no, v_dept_code, v_can_read_contents, v_stakeholder_user_id
|
||||
FROM cb_agent_bearer_key k
|
||||
JOIN cb_app_user u ON u.user_id = k.user_id
|
||||
WHERE k.key_hash = STANDARD_HASH(p_bearer_key, 'SHA256')
|
||||
AND k.active = 'Y'
|
||||
AND k.revoked_at IS NULL
|
||||
AND (k.expires_at IS NULL OR k.expires_at > SYSDATE)
|
||||
AND u.active = 'Y';
|
||||
|
||||
-- USER_ID를 먼저 넣어야 KB_STAKEHOLDERS 자체가 VPD 보호된 뒤에도
|
||||
-- 해당 주체의 자기 행만 안전하게 해석할 수 있다.
|
||||
set_user_values(v_user_id, v_emp_no, v_dept_code, v_can_read_contents);
|
||||
|
||||
IF v_stakeholder_user_id IS NOT NULL THEN
|
||||
DBMS_SESSION.SET_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_USER_ID', v_stakeholder_user_id);
|
||||
SELECT role, channel
|
||||
INTO v_stakeholder_role, v_stakeholder_channel
|
||||
FROM poc_2.kb_stakeholders
|
||||
WHERE user_id = v_stakeholder_user_id;
|
||||
set_stakeholder_context(v_stakeholder_user_id, v_stakeholder_role, v_stakeholder_channel);
|
||||
END IF;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
clear_user;
|
||||
RAISE_APPLICATION_ERROR(-20002, 'Invalid or expired Bearer key');
|
||||
END;
|
||||
END;
|
||||
/
|
||||
SHOW ERRORS PACKAGE BODY cb_agent_ctx_pkg
|
||||
|
||||
PROMPT === 3. Syncing stakeholder bridge and example permissions ===
|
||||
DECLARE
|
||||
v_designer_role_id NUMBER;
|
||||
v_manager_role_id NUMBER;
|
||||
v_object_id NUMBER;
|
||||
v_user_id NUMBER;
|
||||
|
||||
PROCEDURE ensure_role(
|
||||
p_role_name IN VARCHAR2,
|
||||
p_max_level IN VARCHAR2,
|
||||
p_role_id OUT NUMBER
|
||||
) IS
|
||||
BEGIN
|
||||
SELECT role_id INTO p_role_id
|
||||
FROM cb_app_role
|
||||
WHERE role_name = p_role_name;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
SELECT NVL(MAX(role_id), 0) + 1 INTO p_role_id FROM cb_app_role;
|
||||
INSERT INTO cb_app_role(role_id, role_name, max_sensitivity_level)
|
||||
VALUES (p_role_id, p_role_name, p_max_level);
|
||||
END;
|
||||
|
||||
PROCEDURE ensure_object(
|
||||
p_object_name IN VARCHAR2,
|
||||
p_description IN VARCHAR2,
|
||||
p_object_id OUT NUMBER
|
||||
) IS
|
||||
BEGIN
|
||||
SELECT object_id INTO p_object_id
|
||||
FROM cb_protected_object
|
||||
WHERE owner = 'POC_2'
|
||||
AND object_name = p_object_name;
|
||||
|
||||
UPDATE cb_protected_object
|
||||
SET enabled_yn = 'Y',
|
||||
ords_path = 'cb-ords/cb-object-query/poc_2/' || LOWER(p_object_name),
|
||||
description = p_description
|
||||
WHERE object_id = p_object_id;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
SELECT NVL(MAX(object_id), 0) + 1 INTO p_object_id FROM cb_protected_object;
|
||||
INSERT INTO cb_protected_object(
|
||||
object_id, owner, object_name, ords_path, enabled_yn, description
|
||||
) VALUES (
|
||||
p_object_id, 'POC_2', p_object_name,
|
||||
'cb-ords/cb-object-query/poc_2/' || LOWER(p_object_name), 'Y', p_description
|
||||
);
|
||||
END;
|
||||
|
||||
FUNCTION is_sensitive(p_object_name IN VARCHAR2, p_column_name IN VARCHAR2) RETURN CHAR IS
|
||||
BEGIN
|
||||
IF (p_object_name = 'KB_CUSTOMERS' AND p_column_name IN ('CUST_NM', 'RRN_MASKED'))
|
||||
OR (p_object_name = 'KB_CLAIMS' AND p_column_name IN ('CLAIM_AMT', 'PAID_AMT'))
|
||||
OR (p_object_name = 'KB_EXTERNAL_HOLDINGS'
|
||||
AND p_column_name IN ('EXT_INSURER', 'EXT_PRODUCT_GRP', 'EXT_PRODUCT_TYPE')) THEN
|
||||
RETURN 'Y';
|
||||
END IF;
|
||||
RETURN 'N';
|
||||
END;
|
||||
|
||||
PROCEDURE ensure_columns(p_object_name IN VARCHAR2, p_object_id IN NUMBER) IS
|
||||
v_column_id NUMBER;
|
||||
v_count NUMBER;
|
||||
v_sensitive CHAR(1);
|
||||
BEGIN
|
||||
FOR c IN (
|
||||
SELECT column_name
|
||||
FROM all_tab_columns
|
||||
WHERE owner = 'POC_2'
|
||||
AND table_name = p_object_name
|
||||
ORDER BY column_id
|
||||
) LOOP
|
||||
v_sensitive := is_sensitive(p_object_name, c.column_name);
|
||||
SELECT COUNT(*) INTO v_count
|
||||
FROM cb_protected_column
|
||||
WHERE object_id = p_object_id
|
||||
AND column_name = c.column_name;
|
||||
|
||||
IF v_count = 0 THEN
|
||||
SELECT NVL(MAX(column_id), 0) + 1 INTO v_column_id FROM cb_protected_column;
|
||||
INSERT INTO cb_protected_column(
|
||||
column_id, object_id, column_name, sensitive_yn, sensitivity_level, redaction_method
|
||||
) VALUES (
|
||||
v_column_id, p_object_id, c.column_name, v_sensitive,
|
||||
CASE v_sensitive WHEN 'Y' THEN 'CONFIDENTIAL' ELSE 'PUBLIC' END,
|
||||
CASE v_sensitive WHEN 'Y' THEN 'NULLIFY' ELSE 'NONE' END
|
||||
);
|
||||
ELSIF v_sensitive = 'Y' THEN
|
||||
UPDATE cb_protected_column
|
||||
SET sensitive_yn = 'Y', sensitivity_level = 'CONFIDENTIAL', redaction_method = 'NULLIFY'
|
||||
WHERE object_id = p_object_id
|
||||
AND column_name = c.column_name;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END;
|
||||
|
||||
PROCEDURE ensure_user_role(p_user_id IN NUMBER, p_role_id IN NUMBER) IS
|
||||
v_count NUMBER;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO v_count
|
||||
FROM cb_user_role
|
||||
WHERE user_id = p_user_id
|
||||
AND role_id = p_role_id;
|
||||
IF v_count = 0 THEN
|
||||
INSERT INTO cb_user_role(user_id, role_id) VALUES (p_user_id, p_role_id);
|
||||
END IF;
|
||||
END;
|
||||
|
||||
PROCEDURE ensure_permission(
|
||||
p_role_id IN NUMBER,
|
||||
p_target_name IN VARCHAR2,
|
||||
p_rule_column IN VARCHAR2,
|
||||
p_rule_type IN VARCHAR2
|
||||
) IS
|
||||
v_permission_id NUMBER;
|
||||
BEGIN
|
||||
SELECT perm_id INTO v_permission_id
|
||||
FROM cb_permission
|
||||
WHERE role_id = p_role_id
|
||||
AND target_name = p_target_name
|
||||
AND action_name = 'SELECT';
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
SELECT cb_permission_seq.NEXTVAL INTO v_permission_id FROM dual;
|
||||
INSERT INTO cb_permission(perm_id, role_id, target_name, action_name, permission_effect)
|
||||
VALUES (v_permission_id, p_role_id, p_target_name, 'SELECT', 'ALLOW');
|
||||
INSERT INTO cb_permission_rule(rule_id, perm_id, rule_column, rule_type, rule_value)
|
||||
VALUES (cb_permission_rule_seq.NEXTVAL, v_permission_id, p_rule_column, p_rule_type, NULL);
|
||||
END;
|
||||
BEGIN
|
||||
ensure_role('KB_DESIGNER_ROLE', 'CONFIDENTIAL', v_designer_role_id);
|
||||
ensure_role('KB_BRANCH_MANAGER_ROLE', 'CONFIDENTIAL', v_manager_role_id);
|
||||
|
||||
FOR s IN (
|
||||
SELECT user_id, user_nm, role, channel
|
||||
FROM poc_2.kb_stakeholders
|
||||
ORDER BY user_id
|
||||
) LOOP
|
||||
BEGIN
|
||||
SELECT user_id INTO v_user_id
|
||||
FROM cb_app_user
|
||||
WHERE stakeholder_user_id = s.user_id;
|
||||
|
||||
UPDATE cb_app_user
|
||||
SET user_name = s.user_nm,
|
||||
employee_no = s.user_id,
|
||||
dept_code = s.channel,
|
||||
active = 'Y'
|
||||
WHERE user_id = v_user_id;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
SELECT NVL(MAX(user_id), 0) + 1 INTO v_user_id FROM cb_app_user;
|
||||
INSERT INTO cb_app_user(
|
||||
user_id, user_name, employee_no, dept_code, stakeholder_user_id, can_read_contents, active
|
||||
) VALUES (
|
||||
v_user_id, s.user_nm, s.user_id, s.channel, s.user_id, 'N', 'Y'
|
||||
);
|
||||
END;
|
||||
|
||||
IF s.role = '지점장' THEN
|
||||
ensure_user_role(v_user_id, v_manager_role_id);
|
||||
ELSIF s.role = '설계사' THEN
|
||||
ensure_user_role(v_user_id, v_designer_role_id);
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
FOR o IN (
|
||||
SELECT 'KB_STAKEHOLDERS' object_name, '토큰 업무 주체·역할·채널 원장' description FROM dual
|
||||
UNION ALL SELECT 'KB_CUSTOMERS', '고객 기본정보 원장' FROM dual
|
||||
UNION ALL SELECT 'KB_PRODUCTS', '보험상품 마스터' FROM dual
|
||||
UNION ALL SELECT 'KB_CONTRACTS', '보험계약 원장' FROM dual
|
||||
UNION ALL SELECT 'KB_COVERAGES', '담보·특약 원장' FROM dual
|
||||
UNION ALL SELECT 'KB_CLAIMS', '보험금 청구·지급 원장' FROM dual
|
||||
UNION ALL SELECT 'KB_EXTERNAL_HOLDINGS', '외부보유정보 원장' FROM dual
|
||||
) LOOP
|
||||
ensure_object(o.object_name, o.description, v_object_id);
|
||||
ensure_columns(o.object_name, v_object_id);
|
||||
END LOOP;
|
||||
|
||||
-- 토큰은 모든 이해당사자에게 발급되지만, 아래 역할이 없는 주체는
|
||||
-- 권한 레코드가 없으므로 VPD가 1=0으로 fail-closed 된다.
|
||||
ensure_permission(v_designer_role_id, 'KB_STAKEHOLDERS', 'USER_ID', 'STAKEHOLDER_SELF');
|
||||
ensure_permission(v_manager_role_id, 'KB_STAKEHOLDERS', 'USER_ID', 'STAKEHOLDER_SELF');
|
||||
ensure_permission(v_designer_role_id, 'KB_PRODUCTS', NULL, 'ALL');
|
||||
ensure_permission(v_manager_role_id, 'KB_PRODUCTS', NULL, 'ALL');
|
||||
ensure_permission(v_designer_role_id, 'KB_CONTRACTS', 'FC_ID', 'STAKEHOLDER_SELF');
|
||||
ensure_permission(v_manager_role_id, 'KB_CONTRACTS', 'FC_CHANNEL', 'STAKEHOLDER_CHANNEL');
|
||||
ensure_permission(v_designer_role_id, 'KB_CUSTOMERS', 'CUST_ID', 'STAKEHOLDER_SELF');
|
||||
ensure_permission(v_manager_role_id, 'KB_CUSTOMERS', 'CUST_ID', 'STAKEHOLDER_CHANNEL');
|
||||
ensure_permission(v_designer_role_id, 'KB_COVERAGES', 'CUST_ID', 'STAKEHOLDER_SELF');
|
||||
ensure_permission(v_manager_role_id, 'KB_COVERAGES', 'CUST_ID', 'STAKEHOLDER_CHANNEL');
|
||||
ensure_permission(v_designer_role_id, 'KB_CLAIMS', 'CUST_ID', 'STAKEHOLDER_SELF');
|
||||
ensure_permission(v_manager_role_id, 'KB_CLAIMS', 'CUST_ID', 'STAKEHOLDER_CHANNEL');
|
||||
ensure_permission(v_designer_role_id, 'KB_EXTERNAL_HOLDINGS', 'CUST_ID', 'STAKEHOLDER_SELF');
|
||||
ensure_permission(v_manager_role_id, 'KB_EXTERNAL_HOLDINGS', 'CUST_ID', 'STAKEHOLDER_CHANNEL');
|
||||
END;
|
||||
/
|
||||
COMMIT;
|
||||
|
||||
PROMPT === 4. Applying row VPD policies to KB business tables ===
|
||||
DECLARE
|
||||
PROCEDURE replace_row_policy(p_object_name IN VARCHAR2) IS
|
||||
BEGIN
|
||||
BEGIN
|
||||
DBMS_RLS.DROP_POLICY(
|
||||
object_schema => 'POC_2', object_name => p_object_name,
|
||||
policy_name => 'KB_' || p_object_name || '_ROW_POLICY'
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN NULL;
|
||||
END;
|
||||
DBMS_RLS.ADD_POLICY(
|
||||
object_schema => 'POC_2',
|
||||
object_name => p_object_name,
|
||||
policy_name => 'KB_' || p_object_name || '_ROW_POLICY',
|
||||
function_schema => USER,
|
||||
policy_function => 'CB_AGENT_DOC_VPD_FILTER',
|
||||
statement_types => 'SELECT',
|
||||
policy_type => DBMS_RLS.DYNAMIC,
|
||||
enable => TRUE
|
||||
);
|
||||
END;
|
||||
BEGIN
|
||||
replace_row_policy('KB_STAKEHOLDERS');
|
||||
replace_row_policy('KB_CUSTOMERS');
|
||||
replace_row_policy('KB_PRODUCTS');
|
||||
replace_row_policy('KB_CONTRACTS');
|
||||
replace_row_policy('KB_COVERAGES');
|
||||
replace_row_policy('KB_CLAIMS');
|
||||
replace_row_policy('KB_EXTERNAL_HOLDINGS');
|
||||
END;
|
||||
/
|
||||
|
||||
PROMPT === 5. Applying column NULL policies from permission display exceptions ===
|
||||
-- ADB rejects application PL/SQL functions inside DBMS_REDACT expressions.
|
||||
-- SEC_RELEVANT_COL_OPT=ALL_ROWS is the VPD equivalent: it retains the row
|
||||
-- but returns NULL for the protected column while the column predicate is false.
|
||||
CREATE OR REPLACE FUNCTION cb_kb_cust_nm_cls(p_schema IN VARCHAR2, p_object IN VARCHAR2)
|
||||
RETURN VARCHAR2 AUTHID DEFINER AS
|
||||
BEGIN
|
||||
RETURN CASE WHEN cb_agent_can_read_column('KB_CUSTOMERS', 'CUST_NM') = 'Y' THEN '1 = 1' ELSE '1 = 0' END;
|
||||
END;
|
||||
/
|
||||
CREATE OR REPLACE FUNCTION cb_kb_rrn_cls(p_schema IN VARCHAR2, p_object IN VARCHAR2)
|
||||
RETURN VARCHAR2 AUTHID DEFINER AS
|
||||
BEGIN
|
||||
RETURN CASE WHEN cb_agent_can_read_column('KB_CUSTOMERS', 'RRN_MASKED') = 'Y' THEN '1 = 1' ELSE '1 = 0' END;
|
||||
END;
|
||||
/
|
||||
CREATE OR REPLACE FUNCTION cb_kb_claim_amt_cls(p_schema IN VARCHAR2, p_object IN VARCHAR2)
|
||||
RETURN VARCHAR2 AUTHID DEFINER AS
|
||||
BEGIN
|
||||
RETURN CASE WHEN cb_agent_can_read_column('KB_CLAIMS', 'CLAIM_AMT') = 'Y' THEN '1 = 1' ELSE '1 = 0' END;
|
||||
END;
|
||||
/
|
||||
CREATE OR REPLACE FUNCTION cb_kb_paid_amt_cls(p_schema IN VARCHAR2, p_object IN VARCHAR2)
|
||||
RETURN VARCHAR2 AUTHID DEFINER AS
|
||||
BEGIN
|
||||
RETURN CASE WHEN cb_agent_can_read_column('KB_CLAIMS', 'PAID_AMT') = 'Y' THEN '1 = 1' ELSE '1 = 0' END;
|
||||
END;
|
||||
/
|
||||
CREATE OR REPLACE FUNCTION cb_kb_ext_insurer_cls(p_schema IN VARCHAR2, p_object IN VARCHAR2)
|
||||
RETURN VARCHAR2 AUTHID DEFINER AS
|
||||
BEGIN
|
||||
RETURN CASE WHEN cb_agent_can_read_column('KB_EXTERNAL_HOLDINGS', 'EXT_INSURER') = 'Y' THEN '1 = 1' ELSE '1 = 0' END;
|
||||
END;
|
||||
/
|
||||
CREATE OR REPLACE FUNCTION cb_kb_ext_product_grp_cls(p_schema IN VARCHAR2, p_object IN VARCHAR2)
|
||||
RETURN VARCHAR2 AUTHID DEFINER AS
|
||||
BEGIN
|
||||
RETURN CASE WHEN cb_agent_can_read_column('KB_EXTERNAL_HOLDINGS', 'EXT_PRODUCT_GRP') = 'Y' THEN '1 = 1' ELSE '1 = 0' END;
|
||||
END;
|
||||
/
|
||||
CREATE OR REPLACE FUNCTION cb_kb_ext_product_type_cls(p_schema IN VARCHAR2, p_object IN VARCHAR2)
|
||||
RETURN VARCHAR2 AUTHID DEFINER AS
|
||||
BEGIN
|
||||
RETURN CASE WHEN cb_agent_can_read_column('KB_EXTERNAL_HOLDINGS', 'EXT_PRODUCT_TYPE') = 'Y' THEN '1 = 1' ELSE '1 = 0' END;
|
||||
END;
|
||||
/
|
||||
|
||||
DECLARE
|
||||
PROCEDURE replace_column_policy(
|
||||
p_object_name IN VARCHAR2,
|
||||
p_column_name IN VARCHAR2,
|
||||
p_policy_name IN VARCHAR2,
|
||||
p_function_name IN VARCHAR2
|
||||
) IS
|
||||
BEGIN
|
||||
BEGIN
|
||||
DBMS_RLS.DROP_POLICY(
|
||||
object_schema => 'POC_2', object_name => p_object_name, policy_name => p_policy_name
|
||||
);
|
||||
EXCEPTION WHEN OTHERS THEN NULL;
|
||||
END;
|
||||
DBMS_RLS.ADD_POLICY(
|
||||
object_schema => 'POC_2',
|
||||
object_name => p_object_name,
|
||||
policy_name => p_policy_name,
|
||||
function_schema => USER,
|
||||
policy_function => p_function_name,
|
||||
statement_types => 'SELECT',
|
||||
policy_type => DBMS_RLS.DYNAMIC,
|
||||
sec_relevant_cols => p_column_name,
|
||||
sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS,
|
||||
enable => TRUE
|
||||
);
|
||||
END;
|
||||
BEGIN
|
||||
replace_column_policy('KB_CUSTOMERS', 'CUST_NM', 'KB_CUST_NM_CLS_POLICY', 'CB_KB_CUST_NM_CLS');
|
||||
replace_column_policy('KB_CUSTOMERS', 'RRN_MASKED', 'KB_RRN_CLS_POLICY', 'CB_KB_RRN_CLS');
|
||||
replace_column_policy('KB_CLAIMS', 'CLAIM_AMT', 'KB_CLAIM_AMT_CLS_POLICY', 'CB_KB_CLAIM_AMT_CLS');
|
||||
replace_column_policy('KB_CLAIMS', 'PAID_AMT', 'KB_PAID_AMT_CLS_POLICY', 'CB_KB_PAID_AMT_CLS');
|
||||
replace_column_policy('KB_EXTERNAL_HOLDINGS', 'EXT_INSURER', 'KB_EXT_INSURER_CLS_POLICY', 'CB_KB_EXT_INSURER_CLS');
|
||||
replace_column_policy('KB_EXTERNAL_HOLDINGS', 'EXT_PRODUCT_GRP', 'KB_EXT_PRODUCT_GRP_CLS_POLICY', 'CB_KB_EXT_PRODUCT_GRP_CLS');
|
||||
replace_column_policy('KB_EXTERNAL_HOLDINGS', 'EXT_PRODUCT_TYPE', 'KB_EXT_PRODUCT_TYPE_CLS_POLICY', 'CB_KB_EXT_PRODUCT_TYPE_CLS');
|
||||
END;
|
||||
/
|
||||
|
||||
PROMPT === 6. Example configuration summary ===
|
||||
SELECT r.role_name,
|
||||
p.target_name,
|
||||
pr.rule_column,
|
||||
pr.rule_type,
|
||||
NVL(pr.rule_value, '-') AS rule_value
|
||||
FROM cb_permission p
|
||||
JOIN cb_app_role r ON r.role_id = p.role_id
|
||||
JOIN cb_permission_rule pr ON pr.perm_id = p.perm_id
|
||||
WHERE r.role_name IN ('KB_DESIGNER_ROLE', 'KB_BRANCH_MANAGER_ROLE')
|
||||
ORDER BY r.role_name, p.target_name, pr.rule_id;
|
||||
|
||||
PROMPT === KB stakeholder token permission example complete ===
|
||||
Reference in New Issue
Block a user