[Developer] #619 map VPD rules to token context variables
This commit is contained in:
@@ -24,7 +24,7 @@ public class PermissionService {
|
||||
"ALL", "=", "!=", "MY_DEPT", "SELF", "DEPT", "EMP_NO", "TAG",
|
||||
"STAKEHOLDER_SELF", "STAKEHOLDER_CHANNEL");
|
||||
private static final Set<String> VALUE_REQUIRED_RULE_TYPES = Set.of(
|
||||
"=", "!=", "DEPT", "EMP_NO", "TAG");
|
||||
"=", "!=", "DEPT", "EMP_NO", "TAG", "STAKEHOLDER_SELF", "STAKEHOLDER_CHANNEL");
|
||||
private static final Set<String> DEFAULT_COLUMN_RULE_TYPES = Set.of(
|
||||
"MY_DEPT", "SELF", "DEPT", "EMP_NO", "TAG");
|
||||
private static final Set<String> PERMISSION_EFFECTS = Set.of("ALLOW", "DENY");
|
||||
|
||||
@@ -93,13 +93,27 @@
|
||||
WHEN pr2.rule_type = 'TAG' THEN 'REGEXP_LIKE(UPPER('
|
||||
|| NVL(pr2.rule_column, 'TECH_TAG')
|
||||
|| '), ''(^|,)' || REPLACE(UPPER(pr2.rule_value), '''', '''''') || '(,|$)'')'
|
||||
WHEN pr2.rule_type = 'STAKEHOLDER_SELF' THEN pr2.rule_column
|
||||
|| ' = token stakeholder / 담당계약'
|
||||
WHEN pr2.rule_type = 'STAKEHOLDER_CHANNEL' THEN pr2.rule_column
|
||||
|| ' = token stakeholder channel / 담당계약'
|
||||
WHEN pr2.rule_type = 'STAKEHOLDER_SELF' AND pr2.rule_column = 'FC_ID' THEN
|
||||
'(SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_ROLE'') = ''' || NVL(pr2.rule_value, '[역할값 필요]') || ''' '
|
||||
|| 'AND FC_ID = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_USER_ID''))'
|
||||
WHEN pr2.rule_type = 'STAKEHOLDER_SELF' AND pr2.rule_column = 'USER_ID' THEN
|
||||
'(USER_ID = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_USER_ID''))'
|
||||
WHEN pr2.rule_type = 'STAKEHOLDER_CHANNEL' AND pr2.rule_column = 'FC_CHANNEL' THEN
|
||||
'(SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_ROLE'') = ''' || NVL(pr2.rule_value, '[역할값 필요]') || ''' '
|
||||
|| 'AND FC_CHANNEL = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_CHANNEL''))'
|
||||
WHEN pr2.rule_type = 'STAKEHOLDER_SELF' THEN
|
||||
'EXISTS (SELECT 1 FROM POC_2.KB_CONTRACTS c '
|
||||
|| 'WHERE c.' || pr2.rule_column || ' = [CURRENT_ROW].' || pr2.rule_column || ' '
|
||||
|| 'AND SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_ROLE'') = ''' || NVL(pr2.rule_value, '[역할값 필요]') || ''' '
|
||||
|| 'AND c.FC_ID = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_USER_ID''))'
|
||||
WHEN pr2.rule_type = 'STAKEHOLDER_CHANNEL' THEN
|
||||
'EXISTS (SELECT 1 FROM POC_2.KB_CONTRACTS c '
|
||||
|| 'WHERE c.' || pr2.rule_column || ' = [CURRENT_ROW].' || pr2.rule_column || ' '
|
||||
|| 'AND SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_ROLE'') = ''' || NVL(pr2.rule_value, '[역할값 필요]') || ''' '
|
||||
|| 'AND c.FC_CHANNEL = SYS_CONTEXT(''CB_AGENT_CTX'', ''STAKEHOLDER_CHANNEL''))'
|
||||
ELSE pr2.rule_column || ' ' || pr2.rule_type || ' ' || pr2.rule_value
|
||||
END,
|
||||
CHR(10) || 'AND '
|
||||
CHR(10) || 'OR '
|
||||
) WITHIN GROUP (ORDER BY pr2.rule_id)
|
||||
FROM cb_permission_rule pr2
|
||||
WHERE pr2.perm_id = p.perm_id
|
||||
|
||||
@@ -388,7 +388,7 @@ function syncRuleTypeHints(root = document) {
|
||||
}
|
||||
|
||||
const type = typeSelect.value;
|
||||
const valueRequired = ['=', '!=', 'DEPT', 'EMP_NO', 'TAG'].includes(type);
|
||||
const valueRequired = ['=', '!=', 'DEPT', 'EMP_NO', 'TAG', 'STAKEHOLDER_SELF', 'STAKEHOLDER_CHANNEL'].includes(type);
|
||||
const columnOptional = ['ALL', 'MY_DEPT', 'SELF', 'DEPT', 'EMP_NO', 'TAG'].includes(type);
|
||||
const placeholderByType = {
|
||||
ALL: '값 불필요',
|
||||
@@ -397,15 +397,15 @@ function syncRuleTypeHints(root = document) {
|
||||
DEPT: '예: HR',
|
||||
EMP_NO: '예: E2001',
|
||||
TAG: '예: SPRING_BOOT',
|
||||
STAKEHOLDER_SELF: '토큰 이해당사자에서 자동 계산',
|
||||
STAKEHOLDER_CHANNEL: '토큰 채널에서 자동 계산',
|
||||
STAKEHOLDER_SELF: '예: 설계사',
|
||||
STAKEHOLDER_CHANNEL: '예: 지점장',
|
||||
'=': '비교 값',
|
||||
'!=': '비교 값'
|
||||
};
|
||||
|
||||
columnSelect.required = !columnOptional;
|
||||
valueInput.required = valueRequired;
|
||||
valueInput.disabled = ['ALL', 'MY_DEPT', 'SELF', 'STAKEHOLDER_SELF', 'STAKEHOLDER_CHANNEL'].includes(type);
|
||||
valueInput.disabled = ['ALL', 'MY_DEPT', 'SELF'].includes(type);
|
||||
valueInput.placeholder = placeholderByType[type] || '비교 값';
|
||||
if (valueInput.disabled) {
|
||||
valueInput.value = '';
|
||||
@@ -705,9 +705,12 @@ function collectWizardRules(root) {
|
||||
if (type === 'ALL') {
|
||||
return 'ALL';
|
||||
}
|
||||
if (['MY_DEPT', 'SELF', 'STAKEHOLDER_SELF', 'STAKEHOLDER_CHANNEL'].includes(type)) {
|
||||
if (['MY_DEPT', 'SELF'].includes(type)) {
|
||||
return `${displayColumn} ${type}`;
|
||||
}
|
||||
if (['STAKEHOLDER_SELF', 'STAKEHOLDER_CHANNEL'].includes(type)) {
|
||||
return `${displayColumn} ${type} 역할=${value}`;
|
||||
}
|
||||
if (type === 'TAG') {
|
||||
return `${displayColumn} TAG ${value.toUpperCase()}`;
|
||||
}
|
||||
@@ -740,10 +743,10 @@ function collectWizardPredicates(root) {
|
||||
return `${displayColumn} = SYS_CONTEXT('CB_AGENT_CTX', 'EMP_NO')`;
|
||||
}
|
||||
if (type === 'STAKEHOLDER_SELF') {
|
||||
return `${displayColumn} = SYS_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_USER_ID') 또는 담당계약 EXISTS`;
|
||||
return `EXISTS (KB_CONTRACTS c: c.${displayColumn} = <현재행>.${displayColumn} AND TOKEN_ROLE = '${value}' AND c.FC_ID = TOKEN_STAKEHOLDER_ID)`;
|
||||
}
|
||||
if (type === 'STAKEHOLDER_CHANNEL') {
|
||||
return `${displayColumn} = SYS_CONTEXT('CB_AGENT_CTX', 'STAKEHOLDER_CHANNEL') 또는 담당계약 EXISTS`;
|
||||
return `EXISTS (KB_CONTRACTS c: c.${displayColumn} = <현재행>.${displayColumn} AND TOKEN_ROLE = '${value}' AND c.FC_CHANNEL = TOKEN_CHANNEL)`;
|
||||
}
|
||||
if (type === 'DEPT' || type === 'EMP_NO') {
|
||||
return `${displayColumn} = ${sqlLiteral(value)}`;
|
||||
@@ -869,7 +872,7 @@ function permissionWizardRuleValidationMessage(wizard) {
|
||||
if (values.some((rule) => rule.type === 'ALL') && values.length > 1) {
|
||||
return 'ALL 규칙은 다른 조건 규칙과 함께 저장할 수 없습니다. ALL만 남기거나 ALL을 삭제하세요.';
|
||||
}
|
||||
const valueRequired = ['=', '!=', 'DEPT', 'EMP_NO', 'TAG'];
|
||||
const valueRequired = ['=', '!=', 'DEPT', 'EMP_NO', 'TAG', 'STAKEHOLDER_SELF', 'STAKEHOLDER_CHANNEL'];
|
||||
const seen = new Set();
|
||||
for (const [index, rule] of values.entries()) {
|
||||
const position = index + 1;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<h1>접근 규칙</h1>
|
||||
<details class="explanation-details">
|
||||
<summary>도움말</summary>
|
||||
<p>VPD policy function이 참조할 사용자, 역할, 행 규칙, 컬럼 원문 허용 규칙을 저장합니다. KB 원장 예제에서 <code>STAKEHOLDER_SELF</code>는 토큰의 이해당사자 ID, <code>STAKEHOLDER_CHANNEL</code>은 역할에 연결된 채널로 행 범위를 계산합니다.</p>
|
||||
<p>VPD policy function이 참조할 사용자, 역할, 행 규칙, 컬럼 원문 허용 규칙을 저장합니다. KB 원장 예제는 토큰 주체에서 한 번 해석한 이해당사자 ID·역할·채널을 secure context로 사용하고, 대상 고객은 계약원장으로만 연결합니다. <code>STAKEHOLDER_SELF</code>와 <code>STAKEHOLDER_CHANNEL</code>은 각각의 역할 분기로 만들고 허용 분기끼리는 OR로 계산합니다.</p>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
</div>
|
||||
<details class="explanation-details">
|
||||
<summary>행 규칙과 기술 태그 OR 조건 보기</summary>
|
||||
<p class="wizard-hint">특정 기술 태그는 기본적으로 <code>TECH_TAG</code> 컬럼을 봅니다. 같은 ALLOW 권한에 태그를 여러 개 추가하면 “태그 A 또는 태그 B”로 조회됩니다. <code>이해당사자 본인 담당</code>은 <code>FC_ID</code>를 직접 비교하거나 <code>CUST_ID</code>/<code>CONTRACT_NO</code>를 계약원장에 안전하게 연결합니다. <code>이해당사자 채널 범위</code>도 같은 방식으로 <code>FC_CHANNEL</code>을 비교합니다. 두 이해당사자 규칙은 비교할 컬럼을 반드시 선택하세요.</p>
|
||||
<p class="wizard-hint">특정 기술 태그는 기본적으로 <code>TECH_TAG</code> 컬럼을 봅니다. 같은 ALLOW 권한에 태그를 여러 개 추가하면 “태그 A 또는 태그 B”로 조회됩니다. 이해당사자 규칙은 <strong>비교 컬럼</strong>과 <strong>업무 역할값</strong>(예: 설계사, 지점장)을 모두 입력하세요. 토큰을 해석한 뒤 <code>STAKEHOLDER_USER_ID</code>·<code>STAKEHOLDER_ROLE</code>·<code>STAKEHOLDER_CHANNEL</code> context를 사용합니다. <code>STAKEHOLDER_SELF</code>은 <code>c.FC_ID = context 사용자</code>, <code>STAKEHOLDER_CHANNEL</code>은 <code>c.FC_CHANNEL = context 채널</code>이며 서로 다른 허용 규칙은 OR로 결합됩니다.</p>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
@@ -241,6 +241,7 @@
|
||||
|
||||
<section class="content-band">
|
||||
<h2>접근 규칙 목록</h2>
|
||||
<p class="section-subtitle">같은 보호 대상에 적용되는 ALLOW 역할 분기와 한 권한 안의 여러 행 규칙은 OR로 합칩니다. 예를 들어 설계사 본인계약 분기 또는 지점장 채널 분기 중 하나라도 성립하면 행이 허용됩니다. DENY 분기는 허용 결과에서 별도로 제외됩니다.</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm align-middle permission-list-table">
|
||||
<thead>
|
||||
|
||||
Reference in New Issue
Block a user