forked from baron/baron-sso
headless login으로 리펙토링
This commit is contained in:
140
README.md
140
README.md
@@ -2,13 +2,27 @@
|
||||
|
||||
**Baron 로그인**은 화이트 라벨링된 가족사의 모든 소프트웨어 Auth를 총괄하는 사용자 인증/인가 허브입니다.
|
||||
|
||||
## 버그 대응 대원칙 (필수)
|
||||
- 모든 버그 수정은 반드시 **재현 테스트를 먼저 작성**합니다. (Failing test first)
|
||||
- 재현 테스트 없이 코드만 먼저 고치는 행위를 금지합니다.
|
||||
- 수정 후에는 **해당 재현 테스트가 통과할 때까지 반복**해서 원인 분석/수정/검증을 수행합니다.
|
||||
- “테스트 통과”는 최소 기준입니다. 실제 재현 시나리오(로그인, 새로고침, 리다이렉트 등)까지 확인한 뒤에만 이슈를 종료합니다.
|
||||
- 관련 변경이 발생하면 테스트 문서(`docs/test-plan/*`, `docs/trouble-shooting/*`)를 함께 업데이트합니다.
|
||||
## 📂 프로젝트 구조 (Project Structure)
|
||||
|
||||
```
|
||||
baron_sso/
|
||||
├── backend/ # Go Fiber 애플리케이션
|
||||
│ ├── cmd/server/ # 진입점 (Entry point)
|
||||
│ ├── internal/ # 도메인, 핸들러, 저장소(Repository)
|
||||
│ └── Dockerfile
|
||||
├── userfront/ # Flutter 애플리케이션
|
||||
│ ├── src/ # UI 및 로직
|
||||
│ └── pubspec.yaml
|
||||
├── adminfront/ # React 기반 관리
|
||||
│ ├── src/ # UI 및 로직
|
||||
│ └── pubspec.yaml
|
||||
├── gateway/ # Nginx 기반 Gateway (UserFront 프록시)
|
||||
├── compose.ory-stack.yaml # DB 서비스 (Postgres, ClickHouse)
|
||||
├── compose.infra.yaml # DB 서비스 (Postgres, ClickHouse)
|
||||
├── docker-compose.yaml # 앱 서비스 (Front, Back)
|
||||
├── .env.sample # 환경 설정 템플릿
|
||||
└── README.md # 본 파일
|
||||
```
|
||||
* Ory Stack으로 모든 구성요소를 self-hosting 합니다.
|
||||
* Backend는 Go (Fiber)로 구성된 Ory Stack의 유일한 Command 전송 포인트입니다. 모든 Command는 ClickHouse로 강제 전송되며 Audit Log 시스템을 구성합니다.
|
||||
* Front는 Backend를 통해서만 연동하며 자체가 Ory Stack의 RP기도 합니다. 크게 3개 계층으로 분리됩니다.
|
||||
@@ -20,6 +34,7 @@
|
||||
* AdminFront: 사용자 관리 등 Admin 기능
|
||||
* DevFront: RP 관리 등 개발자 기능
|
||||
|
||||
|
||||
## 🏗 아키텍처 (Architecture)
|
||||
|
||||
### 0. Ory Stack
|
||||
@@ -88,6 +103,85 @@ flowchart
|
||||
2.1 향후 App Push 등 2차 인증 강화수단 검토 필요
|
||||
3. **QR Login**: 최초 진입 시 사전 로그인되어 있는 웹/앱을 이용해 QR 코드를 스캔하여, QR코드가 로딩된 Device를 로그인 상태로 전환
|
||||
|
||||
### 5. Headless Login ID/Password Flow
|
||||
- 목적: headless login을 허용한 클라이언트가 자체 로그인 화면에서 `ID/password`를 수집하되, Baron Backend가 OIDC 로그인 흐름만 계속 진행하고 RP에는 `sessionJwt`를 직접 넘기지 않습니다.
|
||||
- 대상 엔드포인트: `POST /api/v1/auth/headless/password/login`
|
||||
- 관련 구현:
|
||||
- `backend/internal/handler/auth_handler.go`
|
||||
- `backend/internal/domain/hydra_models.go`
|
||||
- `backend/internal/handler/auth_handler_login_test.go`
|
||||
|
||||
#### 호출 순서
|
||||
1. RP 브라우저가 Hydra Public의 `/oauth2/auth`를 호출해 OIDC 인증을 시작합니다.
|
||||
2. Hydra가 로그인 단계로 넘긴 `login_challenge`를 RP가 확보합니다.
|
||||
3. RP backend가 자기 private key로 `client_assertion` JWT를 서명합니다.
|
||||
4. RP backend가 Baron Backend의 `POST /api/v1/auth/headless/password/login`에 `client_id`, `client_assertion`, `login_challenge`, `loginId`, `password`를 전송합니다.
|
||||
5. Baron Backend가 Hydra login request와 RP 설정을 검증한 뒤 Kratos sign-in 및 Hydra login accept를 수행합니다.
|
||||
6. 성공 시 Baron Backend는 `redirectTo`만 반환하고, RP 브라우저는 그 URL로 이동해 OIDC 흐름을 이어갑니다.
|
||||
|
||||
#### 요청 바디
|
||||
```json
|
||||
{
|
||||
"client_id": "headless-login-client",
|
||||
"client_assertion": "<signed-jwt>",
|
||||
"login_challenge": "<hydra-login-challenge>",
|
||||
"loginId": "employee001",
|
||||
"password": "secret"
|
||||
}
|
||||
```
|
||||
|
||||
#### 성공 응답
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"provider": "ory",
|
||||
"redirectTo": "https://rp.example.com/callback?code=..."
|
||||
}
|
||||
```
|
||||
|
||||
#### RP / Hydra 선행 조건
|
||||
- Hydra login request의 `client.client_id`와 요청 바디의 `client_id`가 반드시 같아야 합니다.
|
||||
- client가 headless login 선행 조건을 만족해야 합니다.
|
||||
- `headless_token_endpoint_auth_method == "private_key_jwt"` 또는 top-level `token_endpoint_auth_method == "private_key_jwt"`
|
||||
- `headless_jwks_uri` 또는 `headless_jwks`가 존재해야 합니다.
|
||||
- `headless_login_enabled == true`가 필요합니다.
|
||||
- `metadata.status == "inactive"`인 client는 차단됩니다.
|
||||
|
||||
#### `client_assertion` 규칙
|
||||
- 구현상 `client_assertion`은 현재 필수입니다.
|
||||
- JWT claim의 `iss`와 `sub`는 모두 `client_id`와 같아야 합니다.
|
||||
- `exp`는 현재 시각 이후여야 합니다.
|
||||
- `nbf`, `iat`가 있으면 미래 시각이면 안 됩니다.
|
||||
- `aud`는 다음 둘 중 하나와 일치해야 합니다.
|
||||
- `https://<backend-origin>/api/v1/auth/headless/password/login`
|
||||
- `/api/v1/auth/headless/password/login`
|
||||
- 서명 검증용 public key는 `headless_jwks_uri` 또는 `headless_jwks`에서 읽습니다.
|
||||
|
||||
#### 일반 로그인과의 차이
|
||||
- `POST /api/v1/auth/password/login`
|
||||
- UserFront 기본 비밀번호 로그인용입니다.
|
||||
- `login_challenge`가 없으면 `sessionJwt`를 반환합니다.
|
||||
- `login_challenge`가 있으면 Hydra accept 후 `redirectTo`를 반환합니다.
|
||||
- `POST /api/v1/auth/headless/password/login`
|
||||
- headless login 허용 클라이언트 전용입니다.
|
||||
- `client_assertion` 검증이 추가됩니다.
|
||||
- 항상 `sessionJwt` 없이 `redirectTo`만 반환합니다.
|
||||
|
||||
#### 실패 패턴 요약
|
||||
- `400 bad_request`
|
||||
- 필수 필드 누락
|
||||
- `client_assertion` 누락
|
||||
- `401 invalid_client_assertion`
|
||||
- JWKS 조회 실패
|
||||
- 서명 불일치
|
||||
- `aud`/`iss`/`sub`/`exp` 검증 실패
|
||||
- `403 forbidden`
|
||||
- `client_id` 불일치
|
||||
- `headless_login_enabled` 미설정
|
||||
- inactive client
|
||||
- `401 password_or_email_mismatch`
|
||||
- 사용자 인증 실패
|
||||
|
||||
|
||||
### 전체 연결 구조도
|
||||
|
||||
@@ -416,34 +510,12 @@ cd devfront
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📂 프로젝트 구조 (Project Structure)
|
||||
|
||||
```
|
||||
baron_sso/
|
||||
├── backend/ # Go Fiber 애플리케이션
|
||||
│ ├── cmd/server/ # 진입점 (Entry point)
|
||||
│ ├── internal/ # 도메인, 핸들러, 저장소(Repository)
|
||||
│ └── Dockerfile
|
||||
├── userfront/ # Flutter 애플리케이션
|
||||
│ ├── src/ # UI 및 로직
|
||||
│ └── pubspec.yaml
|
||||
├── adminfront/ # React 기반 관리
|
||||
│ ├── src/ # UI 및 로직
|
||||
│ └── pubspec.yaml
|
||||
├── gateway/ # Nginx 기반 Gateway (UserFront 프록시)
|
||||
├── compose.ory-stack.yaml # DB 서비스 (Postgres, ClickHouse)
|
||||
├── compose.infra.yaml # DB 서비스 (Postgres, ClickHouse)
|
||||
├── docker-compose.yaml # 앱 서비스 (Front, Back)
|
||||
├── .env.sample # 환경 설정 템플릿
|
||||
└── README.md # 본 파일
|
||||
```
|
||||
|
||||
## 📝 상태 및 로드맵 (Status & Roadmap)
|
||||
- [x] **Phase 1**: 초기 설정 및 아키텍처 설계 (완료)
|
||||
- [x] **Phase 2**: Backend Audit API 구현 (일부 완료)
|
||||
- [ ] **Phase 3**: userfront 로그인 UI 인증 로직 (예정)
|
||||
- [ ] **Phase 4**: adminfront 기능 추가 (예정)
|
||||
- [ ] **Phase 5**: 대시보드 및 통합 런처 구현 (예정)
|
||||
## 버그 대응 대원칙 (필수)
|
||||
- 모든 버그 수정은 반드시 **재현 테스트를 먼저 작성**합니다. (Failing test first)
|
||||
- 재현 테스트 없이 코드만 먼저 고치는 행위를 금지합니다.
|
||||
- 수정 후에는 **해당 재현 테스트가 통과할 때까지 반복**해서 원인 분석/수정/검증을 수행합니다.
|
||||
- “테스트 통과”는 최소 기준입니다. 실제 재현 시나리오(로그인, 새로고침, 리다이렉트 등)까지 확인한 뒤에만 이슈를 종료합니다.
|
||||
- 관련 변경이 발생하면 테스트 문서(`docs/test-plan/*`, `docs/trouble-shooting/*`)를 함께 업데이트합니다.
|
||||
|
||||
Reference in New Issue
Block a user