From b577568d073c41bd82f0a3c350314ccc8bcc9878 Mon Sep 17 00:00:00 2001 From: kyy Date: Wed, 4 Feb 2026 15:50:16 +0900 Subject: [PATCH] =?UTF-8?q?=ED=81=B4=EB=9D=BC=EC=9D=B4=EC=96=B8=ED=8A=B8?= =?UTF-8?q?=20=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94=20=EB=B0=8F=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=B0=A8=EB=8B=A8=20=ED=9D=90=EB=A6=84=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/client_deactivation_flow.md | 91 ++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 docs/client_deactivation_flow.md diff --git a/docs/client_deactivation_flow.md b/docs/client_deactivation_flow.md new file mode 100644 index 00000000..02c7fec6 --- /dev/null +++ b/docs/client_deactivation_flow.md @@ -0,0 +1,91 @@ +# 클라이언트 비활성화(Deactivation) 및 로그인 차단 흐름 + +이 문서는 관리자가 개발자 포털(`devfront`)에서 특정 클라이언트(RP)를 비활성화했을 때, 해당 앱을 통한 인증 시도가 어떻게 차단되는지 상세 기술 흐름을 설명합니다. + +## 1. 개요 +보안 사고나 점검 등의 사유로 특정 애플리케이션의 접근을 즉시 차단해야 할 경우, 관리자는 클라이언트 목록에서 '상태' 토글을 비활성화할 수 있습니다. 이 설정은 Ory Hydra의 클라이언트 메타데이터에 저장되며, Baron SSO 백엔드 인증 핸들러에서 이를 검증하여 차단을 수행합니다. + +## 2. 전체 동작 흐름 + +```mermaid +sequenceDiagram + participant Admin as 관리자 (DevFront) + participant Backend as 백엔드 (API) + participant Hydra as Ory Hydra (OIDC 엔진) + participant User as 사용자 + participant RP as 애플리케이션 (예: Gitea) + + Note over Admin, Hydra: [1단계: 클라이언트 비활성화 설정] + Admin->>Admin: 상태 스위치 클릭 (활성 -> 비활성) + Admin->>Backend: PATCH /api/v1/dev/clients/{id}/status {status: "inactive"} + Backend->>Hydra: PATCH /admin/clients/{id} (JSON Patch 형식) + Hydra-->>Backend: 업데이트 완료 (metadata.status = "inactive") + Backend-->>Admin: 성공 알림 + + Note over User, Backend: [2단계: 로그인 시도 및 차단] + User->>RP: 로그인 시도 (Baron SSO 선택) + RP->>Hydra: 인증 요청 (/oauth2/auth) + Hydra->>User: 로그인 페이지로 리디렉션 (login_challenge 포함) + User->>Backend: 아이디/비밀번호 입력 및 로그인 요청 + Backend->>Hydra: GetLoginRequest(challenge) 호출 + Hydra-->>Backend: 클라이언트 정보 응답 (Metadata 포함) + + Note right of Backend: 비활성 체크 로직 작동 + Backend->>Backend: Metadata["status"] == "inactive" 확인 + + alt 비활성화 상태인 경우 + Backend-->>User: 403 Forbidden (비활성화된 앱 안내) + Note over User: 로그인 프로세스 중단 + else 활성화 상태인 경우 + Backend->>Hydra: AcceptLoginRequest + Hydra-->>User: 동의 화면 또는 RP로 리디렉션 + end +``` + +## 3. 상세 구현 내용 + +### 3.1. 관리자 UI 및 상태 변경 +- **파일**: `devfront/src/features/clients/ClientsPage.tsx` +- **함수**: `updateStatusMutation` +- **로직**: 사용자가 스위치를 토글하면 `updateClientStatus` API를 호출합니다. 업데이트 중에는 중복 클릭을 방지하기 위해 스위치가 `disabled` 상태가 됩니다. + +### 3.2. 백엔드 상태 업데이트 중계 +- **파일**: `backend/internal/handler/dev_handler.go` +- **함수**: `UpdateClientStatus` +- **로직**: 클라이언트 ID와 변경할 상태값을 받아 `service.HydraAdminService`의 `PatchClientStatus`를 호출합니다. +- **파일**: `backend/internal/service/hydra_admin_service.go` +- **함수**: `PatchClientStatus` +- **로직**: Ory Hydra Admin API 규격에 맞춰 **JSON Patch(RFC 6902)** 형식을 생성합니다. + ```go + payload := []map[string]interface{}{ + {"op": "replace", "path": "/metadata/status", "value": status}, + } + ``` + +### 3.3. 인증 단계별 차단 검증 (핵심 보안 로직) +백엔드는 OIDC 인증 흐름의 3가지 주요 진입점에서 클라이언트의 활성 상태를 매번 체크합니다. + +#### 1) 수동 로그인 시 (`PasswordLogin`) +- **파일**: `backend/internal/handler/auth_handler.go` +- **로직**: 사용자가 직접 아이디/비밀번호를 입력했을 때, `login_challenge`가 있다면 Hydra에 해당 클라이언트 정보를 조회하여 `metadata.status`가 `inactive`인지 확인합니다. + +#### 2) 자동 로그인 시 (`AcceptOidcLoginRequest`) +- **파일**: `backend/internal/handler/auth_handler.go` +- **로직**: 사용자가 이미 SSO 세션을 가지고 있어 자동으로 로그인이 진행될 때 호출됩니다. 승인(Accept)을 보내기 직전에 클라이언트 상태를 체크하여 차단합니다. + +#### 3) 동의 화면 진입 시 (`GetConsentRequest`) +- **파일**: `backend/internal/handler/auth_handler.go` +- **로직**: 로그인 후 권한 동의 화면을 그리기 위해 정보를 가져오는 시점입니다. 비활성화된 앱이라면 정보를 반환하지 않고 에러를 발생시킵니다. + +## 4. 예외 및 에러 처리 +- 클라이언트가 비활성화된 경우 백엔드는 `403 Forbidden` 상태 코드와 함께 `"The client application is disabled."` 메시지를 반환합니다. +- 백엔드 로그에는 `slog.Warn`을 통해 `"Login rejected for inactive client"` 메시지가 기록되어 관리자가 시도 이력을 추적할 수 있습니다. + +## 5. 확인 방법 (테스트 시나리오) +1. `devfront`에서 특정 앱의 스위치를 끕니다. +2. 해당 앱에서 로그인을 시도합니다. +3. 이미 로그인된 상태여도 리디렉션 과정에서 "비활성화된 애플리케이션입니다"라는 안내와 함께 차단되는지 확인합니다. +4. 백엔드 로그에서 차단 기록을 확인합니다: + ```bash + docker compose logs -f backend | grep "inactive client" + ```