# 설계서: 권한체계 중심 VPD 안내와 토큰 검증 흐름 (#557) > **상태**: Approved > **작성**: [AI] Architect · **최종수정**: 2026-06-29 > **추적성** — Redmine: #557 · 관련 ADR: 없음 > · 구현 파일: `ProbeController`, `ProbeResult`, `VpdPolicyService`, 대시보드/VPD/토큰/검증 템플릿 > · 테스트: `ProbeResultTest`, `VpdPolicyServiceTest`, `GuidedFlowTemplateTest` ## 1. 목적 (Why) 권한을 만든 사람의 머릿속 구조를 모르는 운영자도 “누가 어떤 데이터를 볼 수 있는지 정하고, DB가 그대로 제한하는지 확인한다”는 한 흐름으로 제품을 이해하고 사용할 수 있게 한다. ## 2. 범위 (Scope) - **포함**: Macro→Micro 설명 구조, 내비게이션 재분류, 동적 권한 VPD 기본 적용, custom filter 고급 분리, 토큰 검증 단순화, 상태별 일반 문장과 다음 행동, 발급→검증 연결. - **제외**: 권한 데이터 모델 변경, VPD 함수 SQL 알고리즘 변경, 토큰 원문 저장, 운영 DB DDL 자동 실행, ORDS handler 생성 방식 변경. ## 3. 인수조건 (Acceptance Criteria) - [x] 첫 화면에서 권한 설계 → DB 보호 → 토큰 발급 → 결과 확인의 목적과 순서를 이해할 수 있다. - [x] 기본 VPD 적용은 객체만 선택하고 권한체계 동적 함수와 SELECT 정책을 서버가 결정한다. - [x] `CB_AGENT_DOC_VPD_FILTER`는 일반 UI에서 수정할 수 없고 직접 POST도 거부된다. - [x] 별도 filter/predicate와 policy 교체는 사용 기준·안전 규칙이 있는 고급 영역에만 노출된다. - [x] 검증 화면은 등록 토큰 선택 없이 Bearer 원문과 대상만 입력한다. - [x] 검증 결과가 상태, 적용 주체, 행 결과, 다음 행동 순으로 설명되고 HTTP 원문은 접혀 있다. - [x] 존재하지 않는 테스트 토큰은 “DB에 등록된 토큰이 아님”과 재발급 절차를 안내한다. - [x] 발급 직후 토큰 복사와 검증 화면 이동이 명확하다. ## 4. 컨텍스트 & 제약 - 토큰 원문은 보안상 저장하지 않고 SHA-256 hash만 저장한다. 따라서 목록에서 원문을 재선택해 호출하는 기능은 제공하지 않는다. - 권한 원천은 사용자/그룹/역할/권한/규칙 테이블이며 VPD 함수가 요청 시점에 이를 조회한다. - 권한이 없거나 컨텍스트/규칙이 잘못되면 `1=0`으로 닫는 fail-closed 원칙을 유지한다. - 운영 DB의 기존 custom policy는 삭제하지 않고 고급 관리 기능으로 남긴다. ## 5. 아키텍처 개요 ```text [Macro: 무엇을 하려는가] 누가(User/Group) → 어떤 역할(Role) → 어떤 데이터(Object/Rule) │ ▼ [Micro: DB가 어떻게 지키는가] CB_PERMISSION* 테이블 → CB_AGENT_DOC_VPD_FILTER → Oracle VPD │ ▼ [Evidence: 실제로 지켜졌는가] 1회 표시 토큰 → ORDS 호출 → 사용자/역할 + 보이는 행 + 다음 행동 ``` - I/O 경계: controller/service는 DB catalog와 ORDS를 호출한다. - 순수 표현 경계: `ProbeResult`의 상태별 제목·설명·다음 행동은 외부 I/O 없이 테스트한다. - 안전 경계: 기본 endpoint는 동적 함수만 사용하고 custom 함수 생성/교체 endpoint는 고급 기능으로 유지한다. ## 6. 데이터 모델 - 입력: `objectKey`, `bearerToken`, `objectId`, `limit`. - 기본 VPD 명령: policy `CB_PERMISSION_SELECT_POLICY`, function `*.CB_AGENT_DOC_VPD_FILTER`, statements `SELECT`, enabled `true`, update check `false`. - 검증 표현: 기존 `ProbeResult`에 상태별 `title`, `plainSummary`, `nextAction`, `successLike` 계산 메서드를 둔다. - 검증 컨텍스트: hash로 찾은 `TokenContextView`와 `ProtectedObject`를 controller model에 추가한다. 원문은 model/result/log에 저장하지 않는다. ## 7. 함수 명세 (Function Specs) | 함수 | 책임 | 입력 | 출력 | 에러/실패 | 복잡? | |---|---|---|---|---|---| | `createDefaultPermissionPolicy` | 객체에 표준 동적 권한 VPD 연결 | `objectKey` | 없음 | 함수 미설치, 중복/DB 오류 | 단순 | | `saveFilterFunction` guard | 핵심 동적 함수 덮어쓰기 차단 | owner/name/predicate | 없음 | 핵심 함수명이면 `AppException` | 단순 | | `ProbeResult.title/plainSummary/nextAction` | 기술 상태를 일반 문장으로 변환 | status/result | 문자열 | 알 수 없는 상태도 안전 안내 | 단순 | | `findTokenContextByPlainToken` | 원문 hash에 대응하는 사용자/역할 설명 조회 | 토큰 원문 | nullable context | 미등록이면 null | 단순 | | `ProbeController.run` | 단일 토큰 입력으로 실행·설명 model 구성 | form | fragment | status별 결과 fragment | 단순 | ## 8. 흐름 / 알고리즘 1. 운영자는 사용자/그룹/역할과 객체별 행·열 규칙을 저장한다. 2. 보호할 DB 객체를 선택하고 “권한체계 연결”을 누른다. 3. 서버는 설치된 `CB_AGENT_DOC_VPD_FILTER`를 찾아 동적 SELECT policy를 붙인다. 4. 토큰을 발급하면 원문을 한 번 복사하고 검증으로 이동한다. 5. 검증 시 hash로 토큰과 사용자를 식별하고 ORDS를 호출한다. 6. 화면은 사용자/직접 역할/그룹 상속, 보인 행 수 또는 차단 이유, 다음 행동을 먼저 보여준다. 7. HTTP request/response는 문제 분석용 상세 영역에서만 연다. ## 9. 엣지케이스 & 에러 처리 - 토큰 미등록: 환경 파일과 DB가 어긋난 상태로 설명하고 새 발급을 안내한다. - 만료/회수: 새 토큰 발급 또는 활성 토큰 사용을 안내한다. - 0행: 오류가 아니라 VPD가 현재 권한 기준으로 모든 행을 제외했을 가능성을 먼저 설명한다. - ORDS 미설정/경로 오류/접속 실패: 권한 문제와 인프라 문제를 구분한다. - 기존 별도 함수가 ORA-28110을 내는 경우: 토큰 오류와 분리해 `VPD_FILTER_ERROR`로 설명하고 정상 동적 권한 객체를 검증 목록에서 우선한다. - 핵심 함수 미설치: 자동으로 custom predicate를 만들지 않고 설치 상태 확인을 요구한다. - 핵심 함수 수정 시도: UI와 service 양쪽에서 차단한다. ## 10. 테스트 계획 - `ProbeResultTest`: 성공, 0행, 토큰 미등록, 만료, ORDS 장애의 일반 문장/다음 행동. - `VpdPolicyServiceTest`: 핵심 함수 수정 거부, 기본 적용이 표준 policy/function/SELECT/DYNAMIC 옵션을 사용. - `GuidedFlowTemplateTest`: 검증의 단일 token 입력, 기술 상세 접힘, VPD 기본/고급 분리, 대시보드 4단계. - 전체 `mvn test` 34건, `mvn -DskipTests package`. - 실행 환경에서는 로그인 후 주요 페이지 HTTP 200과 실제 신규 토큰 검증을 확인한다. 외부 ORDS가 없으면 상태별 설명까지만 검증한다. ## 11. 리스크 & 대안 검토 - 기존 template 선택 UI를 기본으로 유지하면 유연하지만 일반 사용자가 정책 이름과 함수를 이해해야 한다. 객체만 받는 전용 기본 endpoint를 선택한다. - 목록의 등록 토큰을 선택하게 하려면 원문 저장이 필요해진다. 보안 경계를 유지하고 원문 직접 입력만 제공한다. - custom 기능을 제거하면 기존 운영 정책 관리가 막힌다. 삭제 대신 고급 영역과 서버 안전장치로 격리한다. ## 12. 미해결 질문 (Open Questions) - 실제 환경에서 동적 함수가 연결된 객체는 신규 토큰으로 ORDS/VPD 성공 응답까지 확인했다. - 기존 `BOARD_ASSIGNMENTS_FILTER`는 ORA-28110 상태다. 운영 policy 교체는 DDL 승인 후 별도 Filter 고급 화면에서 표준 동적 함수로 복구해야 한다. - `.env`의 기존 테스트 토큰 두 개는 현재 DB에 없으며, 환경 비밀 교체는 저장소 밖 운영 작업으로 남긴다.