1
0
forked from baron/baron-sso

접근 이력 스크롤 조회 기능 추가

This commit is contained in:
Lectom C Han
2026-02-02 14:03:54 +09:00
parent 7e662c9878
commit 1c0a5ed272
15 changed files with 1265 additions and 231 deletions

View File

@@ -1,22 +1,49 @@
# AGENTS 가이드 (Baron SSO)
## 목적
- Inbound Auth/Launcher와 관리(Admin) 기능을 하나의 백엔드에서 운영하되, 네임스페이스·도메인·권한으로 강하게 분리한다.
- 사용자 플로우(가입/로그인)와 관리 플로우(Descope Management Key 사용)를 명확히 구분해 보안 사고면을 축소한다.
- 인증/인가 허브로서 **Backend + Ory Stack** 중심 아키텍처를 유지
- 사용자 플로우(UserFront)와 관리 플로우(Admin/DevFront)를 명확히 분리
- 네트워크/보안 경계를 문서화해 회귀/설정 오류를 방지
## 현재 원칙
- **경계 분리**: `/admin/*` + admin 서브도메인에서만 관리 기능 노출. 일반 사용자 번들과 관리자 번들(또는 라우트)을 분리.
- **관리 키 취급**: Descope Management Key는 서버 내부에서만 사용, 비동기 잡/관리 API에서 래핑. 모든 관리 액션을 감사 로그/알람/레이트리밋으로 보호.
- **권한/가드**: role/permission 기반 접근 제어. 관리자 세션 TTL은 짧게, step-up MFA 고려.
## 시스템 요약
- **Backend**: Command 단일 진입점, 감사 로그를 ClickHouse에 적재
- **Ory Stack**: Kratos/Hydra/Keto/Oathkeeper (인증/토큰/정책)
- **Front**: UserFront(Flutter)-사용자 접점, AdminFront/DevFront(React)-내부 관리도구
- **원칙**: Front는 Backend API를 통해서만 IDP 기능을 호출
## 인증 플로우 핵심
- **최초 회원가입**: SMS 인증(Enchanted Link/OTP) 필수 → 인증 성공 후 계정 생성 및 초기 세션 발급.
- **재로그인 분기 (앱 세션 보유 + 사용자 선택)**:
- 앱 로그인 상태 + 사용자가 “앱 승인” 선택: 앱을 MFA/IDPW 대체 수단으로 사용(푸시/딥링크 승인) → 승인 시 웹 세션 발급.
- 앱 세션이 없거나, 사용자가 이번 로그인에서 앱을 사용하지 않기로 선택: SMS 또는 이메일/비밀번호 경로로 진행.
- **세션 TTL**: 앱 기반 세션 유지시간을 `APP_SESSION_TTL_MINUTES` 환경 변수로 관리(기본 예: 30분).
## 네트워크/보안 경계
- `ory-net`: Ory 내부 통신 전용 네트워크
- `baron_net`: App(backend/userfront/adminfront/devfront) 네트워크
- `public_net`: Oathkeeper, userfront 외부 공개. Gateway를 이용해 Proxy 분기
## 작업 시 체크리스트
- 관리 기능 개발 시 admin 네임스페이스, 권한 체크, 감사 로깅, 레이트리밋을 기본 포함.
- 인증/로그인 변경 시 “폴백은 사용자 선택일 때만” 규칙을 준수하고, UI에도 선택 흐름을 노출.
- 새 설정/비밀값은 .env.sample에 반영하고 서버에서만 소비하게 설계한다.
핵심 규칙:
- **Ory Admin 포트는 외부 노출 금지** (Backend만 `ory-net`을 통해 접근)
- **UserFront는 Oathkeeper 뒤에 있지 않음**
- **모든 Front(User/Admin/Dev)는 Ory Admin 엔드포인트에 직접 접근하지 않음**
## 인증/세션 핵심
- `IDP_PROVIDER` Ory 전용 저장 구조지만 향후 마이그레이션으로 추가 스택 지원할 수 있음
- `sessionJwt`**JWT가 아닐 수 있음** (Kratos session token은 opaque 가능)
- OIDC Consent 플로우는 UserFront의 `/consent` 경로에서 처리
- 토큰/쿠키 전달 방식 변경 시 `docs/auth-flow.md`를 반드시 갱신
## 작업 체크리스트
- 인증/로그인 변경 시
- `docs/auth-flow.md` 업데이트
- 세션/쿠키/Authorization 전달 방식 영향도 점검
- UserFront가 Ory/Oathkeeper 직접 호출하지 않도록 확인
- Ory 설정 변경 시
- `compose.ory.yaml`, `docker/ory/*` 변경 범위 명시
- `ory-net`/`public_net` 경계 유지 여부 확인
- 환경 변수 추가/변경 시
- `.env.sample` 반영
- 문서/가이드 갱신
- 배포/운영 변경 시
- `Makefile`/compose 실행 절차 영향 확인
- 최소 Smoke 테스트 수행
## 테스트 참고
- 테스트 계획 및 수동 실행 기준은 `docs/test-plan.md`를 따른다.

View File

@@ -11,8 +11,8 @@
| 방식 | Backend 엔드포인트 | 세션 토큰 반환 | 비고 |
|---|---|---|---|
| ID/Password | `POST /api/v1/auth/password/login` | `sessionJwt` | IDP 추상화 사용 (Ory/Descope) |
| Enchanted Link (Email/SMS) | `POST /api/v1/auth/enchanted-link/init``POST /api/v1/auth/enchanted-link/poll` | `sessionJwt` | 링크 클릭 시 `POST /api/v1/auth/magic-link/verify` 호출 |
| Magic Link Verify | `POST /api/v1/auth/magic-link/verify` | `token` | Polling 세션 갱신용 |
| Enchanted Link (Email/SMS) | `POST /api/v1/auth/enchanted-link/init``POST /api/v1/auth/enchanted-link/poll` | `sessionJwt` | Ory는 `/api/v1/auth/login/code/verify`/`verify-short`(verifyOnly) 사용 |
| Magic Link Verify | `POST /api/v1/auth/magic-link/verify` | `token` | 비-Ory 경로(verifyOnly 가능) |
| SMS 코드 | `POST /api/v1/auth/sms``POST /api/v1/auth/verify-sms` | `token` | 현재는 내부 토큰(placeholder). Kratos 세션 교환 필요 |
| QR 로그인 | `POST /api/v1/auth/qr/init``POST /api/v1/auth/qr/poll` | `sessionJwt` | 모바일 승인: `POST /api/v1/auth/qr/approve` |
@@ -27,8 +27,10 @@
### 2.2 Enchanted Link (Email/SMS)
1. `POST /api/v1/auth/enchanted-link/init``pendingRef` 수신
2. `POST /api/v1/auth/enchanted-link/poll`로 폴링
3. 사용자가 링크 클릭하면 UserFront가 `POST /api/v1/auth/magic-link/verify` 호출
4. Polling 응답에서 `sessionJwt` 수신
3. 사용자가 링크 클릭하면 UserFront가 아래 중 하나 호출
- Ory: `POST /api/v1/auth/login/code/verify` 또는 `/api/v1/auth/login/code/verify-short` (verifyOnly=1)
- 비-Ory: `POST /api/v1/auth/magic-link/verify` (verifyOnly=1)
4. Polling 응답에서 `sessionJwt` 수신 (승인 후 Backend에서 세션 발급)
### 2.3 QR 로그인
1. `POST /api/v1/auth/qr/init``qrCode`, `pendingRef` 수신
@@ -75,14 +77,41 @@
---
## 5) UserFront 주의사항
## 5) 링크 로그인 ↔ QR 로그인 공유/분리 로직
### 5.1 공유되는 로직 (공통 기반)
- **IDP 코드 검증 로직 공유**: Ory 기준으로 링크 로그인과 QR 로그인 모두 `VerifyLoginCode`(코드 기반 로그인 검증)를 사용합니다.
- **Kratos courier relay 공유**: Kratos에서 발송되는 `login_code``HandleKratosCourierRelay`에서 처리하며, 링크/QR 모두 이 경로를 거칩니다.
- **코드/플로우 상태 저장**: 코드 로그인 플로우의 `flow_id`는 공통 키(`prefixLoginCode`)에 저장됩니다.
### 5.2 분리되는 로직 (pendingRef/승인 경로)
- **pendingRef 네임스페이스 분리**:
- 링크 로그인: `prefixSession`, `prefixLoginCodePending`, `prefixLoginMethod`, `prefixLoginFlow`
- QR 로그인: `prefixLoginCodeQrPending`, `prefixLoginCodeQr`, `prefixQrPending`, `prefixQrMeta`, `prefixQrApproverSession`
- **승인 엔드포인트 분리**:
- 링크 로그인: `/api/v1/auth/magic-link/verify` 또는 `/api/v1/auth/login/code/verify*` (verify-only)
- QR 로그인: `/api/v1/auth/qr/approve`
- **세션 발급 주체 분리**:
- 링크 로그인: Polling(요청 기기 A)에서 세션 발급
- QR 로그인: Polling(웹)에서 세션 발급, 모바일은 승인만 수행
- **audit 기록 경로 분리**:
- 링크 로그인: `writeLinkAuditLog`
- QR 로그인: `writeQrAuditLog`
### 5.3 verify-only 적용 범위
- 링크 로그인/코드 로그인 경로에만 적용됩니다.
- QR 로그인은 approve/poll 구조이므로 verify-only를 사용하지 않습니다.
---
## 6) UserFront 주의사항
- `sessionJwt`**JWT 형식이 아닐 수 있음** (Kratos session token은 opaque 가능)
- 현재 UserFront는 Descope SDK 기반 세션 처리 로직이 포함되어 있어, Ory 사용 시 이 부분은 분리/대체가 필요함
---
## 6) 다음 액션 제안
## 7) 다음 액션 제안
1. **Kratos 세션 쿠키 전달 방식(A) 구현**
2. Enchanted/Magic Link의 Ory 대응(로그인 코드/링크 방식) 설계

View File

@@ -0,0 +1,35 @@
# #146 원격 링크 로그인 세션/이력 불일치 대응
## 요약
- Ory 링크 로그인은 실제로 `/api/v1/auth/login/code/verify` 또는 `/api/v1/auth/login/code/verify-short` 경로를 사용합니다.
- 기존에는 `verifyOnly``/api/v1/auth/magic-link/verify`에만 적용되어, 링크를 클릭한 기기에서 세션이 발급되는 문제가 있었습니다.
- 인증수단 표기는 loginId 기반 추론에 의존해 SMS 요청이 Email로 표시되는 문제가 있었습니다.
## 원인
- verify-only 적용 범위가 magic link에 한정되어 있었고, Ory 코드 기반 경로는 세션을 즉시 발급했습니다.
- audit 로그의 인증수단 표기는 request_body/loginId 기반 추론만 사용했습니다.
## 변경 사항
### 1) verify-only 범위 확장
- `/api/v1/auth/login/code/verify`, `/api/v1/auth/login/code/verify-short``verifyOnly` 지원 추가
- verify-only일 때는 승인 상태만 저장하고 세션 발급은 Polling(Desktop)에서 수행
### 2) Polling 시 세션 발급 주체 정리
- 승인 상태(`status=approved`)는 **요청한 기기(A)**에서만 세션 발급
- Ory 코드 플로우는 Polling 시점에 `VerifyLoginCode`를 수행해 세션 생성
### 3) 인증수단 표기 개선
- `pendingRef` 기준으로 `login_method`(sms/email), `login_flow`(code/link) 저장
- audit 로그에 해당 메타를 기록하여 SMS/Email, 코드/링크 구분을 명확히 표시
- verify-only 요청 로그는 타임라인에서 제외
## 영향 범위
- Backend: 링크 로그인 승인/세션 발급 경로 변경
- Front: verify-only 플래그 전달 확장
- 문서: auth-flow/test-plan 업데이트
## 테스트 계획 (요약)
- Desktop에서 링크 요청 → Mobile에서 링크 클릭(verifyOnly) → Desktop Polling으로 세션 발급
- Mobile 단말에서 세션/로그인 이력 미생성 확인
- 인증수단 표기(SMS/Email) 정확성 확인
- 코드/링크 만료/재사용 시나리오 점검

132
docs/test-plan.md Normal file
View File

@@ -0,0 +1,132 @@
# 테스트 계획 및 원칙 (Baron SSO)
## 1) 목적
- 인증/인가 핵심 플로우의 안정성과 회귀 방지
- 멀티 서비스(Backend/Ory Stack/Front) 연동 품질 확보
- 릴리즈 기준과 장애 분석 기준의 표준화
## 2) 범위
### 포함
- Backend (Go Fiber)
- UserFront (Flutter Web/App)
- AdminFront / DevFront (React)
- Ory Stack (Kratos/Hydra/Keto/Oathkeeper)
- Gateway/네트워크 구성 (baron_net, ory-net, public_net)
- DB (PostgreSQL, ClickHouse, Redis)
### 제외(별도 계획)
- 외부 IDP 벤더의 장애 대응 (Descope 등)
- 프로덕션 데이터 복구 시나리오(백업/DR)
## 3) 원칙
- **Shift-left**: 개발 단계에서 최대한 조기 검증
- **단계적 신뢰**: Unit → Integration → E2E 순으로 신뢰도 상승
- **환경 분리**: 로컬/스테이징/프로덕션 구성 차이를 문서로 명시
- **결정적 테스트**: 시간/랜덤/외부 의존성 최소화
- **Idempotent**: 반복 실행 시 동일 결과 보장
- **보안 우선**: 민감정보(PII/Token)는 테스트 로그에 노출 금지
- **실패 우선 기록**: 실패 로그/재현 절차를 우선 확보
## 4) 테스트 레이어 및 목표
### 4.1 Unit Test
- Backend: 비즈니스 로직, 유효성 검증, Mapper/Adapter
- Frontend: 유틸/상태관리/컴포넌트 로직
- 목표: 빠른 피드백(수초~수분)
### 4.2 Integration Test
- Backend + DB(Postgres/ClickHouse/Redis)
- Backend + Ory Admin API (Kratos/Hydra/Keto)
- 목표: 네트워크/스토리지 연동 검증
### 4.3 Contract Test
- Backend ↔ Frontend API 스키마/응답 계약 검증
- OIDC/OpenID Connect 표준 응답 형식 검증
### 4.4 E2E Test (Happy/Edge Path)
- 로그인 플로우(Password / Magic Link / SMS / QR)
- Consent 플로우 (Hydra login/consent)
- 토큰 발급/재발급/로그아웃/세션 만료
- 목표: 핵심 사용자 여정의 회귀 방지
### 4.5 Smoke Test
- 배포 직후 필수 엔드포인트 헬스체크
- `GET /health`, Ory readiness, UserFront 정적 리소스
### 4.6 Regression / Non-functional
- 성능: 로그인/토큰 발급 지연, 대량 감사 로그 적재
- 보안: 인증 우회, 권한 상승, 세션 고정 공격
- 관측성: 핵심 로그/메트릭 누락 여부
## 5) 환경 전략
- 로컬: `make up-all` 또는 `docker compose -f compose.infra.yaml -f compose.ory.yaml -f docker-compose.yaml up -d`
- 스테이징: 프로덕션과 동일한 네트워크/도메인 구성
- 프로덕션: 최소한의 smoke/관측성 점검
## 6) 테스트 데이터 정책
- 표준 시드 사용자/테넌트/클라이언트 세트 정의
- PII 마스킹 규칙(이메일/전화번호/토큰)
- 재현용 고정 데이터와 랜덤 데이터 분리
- 테스트 종료 후 클린업 규칙 정의
## 7) 자동화 및 CI/CD 기준 (현행)
- **현재 상태**: 레포에 CI/CD 워크플로우 정의가 없음. 테스트는 로컬/수동 실행 기준으로 운영.
- **CI 변수 활용**: AdminFront/DevFront Playwright 설정은 `CI` 환경 변수에 따라 재시도/워커 수를 조정함.
- **수동 실행 기준**:
- Backend: `go test ./...` (위치: `backend/`)
- UserFront: `flutter test` (위치: `userfront/`)
- AdminFront: `npm test` (Playwright, 위치: `adminfront/`, baseURL `http://localhost:5173`)
- DevFront: `npm test` (Playwright, 위치: `devfront/`, baseURL `http://localhost:5174`)
### 7.1 수동 게이트 제안(현행 기준)
- PR/머지 전 최소 기준: Backend Unit + 해당 Front 테스트(변경 범위)
- 배포 전 최소 기준: Smoke + 핵심 E2E(로그인/Consent)
## 8) 핵심 플로우 테스트 시나리오
### 인증/세션
- Password 로그인 성공/실패/락/재시도
- Magic Link 발송/검증/만료
- SMS 코드 발송/검증/재시도 제한
- QR 승인/거절/타임아웃
- 로그아웃 시 세션/쿠키/토큰 무효화
### 원격 링크 로그인(verify-only)
- Desktop에서 링크 요청 → Mobile에서 링크 클릭(verifyOnly) → Desktop Poll로 세션 발급
- Mobile 단말에 세션 생성/로그인이 발생하지 않는지 확인
- Audit/로그인 이력에 Desktop 세션 ID만 기록되는지 확인
- 인증수단 표기(SMS/Email)가 요청 수단과 일치하는지 확인
- 코드/링크 만료 시 승인 실패 및 재요청 안내
### OIDC/Hydra
- Login Challenge 처리
- Consent 승인/거절
- Token/Refresh Token 발급
- Redirect URI 검증
### 권한/정책(Keto)
- 권한 부여/회수 시 접근 제어 확인
- 관리자/일반 사용자 분리
### 네트워크/프록시
- `baron_net``ory-net` 경계 준수
- Frontend에서 Ory 내부 Admin 포트 접근 불가
## 9) 관측성/장애 대응 테스트
- 에러 로그 구조(필수 필드 포함) 확인
- Audit Log 누락/중복 체크
- 실패 시 재시도 정책 검증
## 10) 책임 및 운영 프로세스
- 각 영역별 오너 지정(Backend/Front/Ory)
- 실패 시 triage 기준: 재현 가능 여부 → 영향도 → 우선순위
- 테스트 케이스/기대 결과는 이슈/PR에 링크
## 11) 유지보수 원칙
- 신규 기능은 반드시 관련 테스트 추가
- 회귀 버그 발생 시 재현 테스트를 우선 추가
- 불안정 테스트는 원인 분석 후 격리 또는 개선
## 12) 체크리스트 (릴리즈 전)
- Smoke 통과
- 핵심 E2E 통과
- 보안 관련 회귀 없음
- 장애/모니터링 대시보드 정상