diff --git a/README.md b/README.md index 40cf80f..1f1a327 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,9 @@ python3 -m http.server 4173 ## 연동 지점 -- SSO: Q&A는 홈페이지 로그인 정보를 전달받지 않고, `https://app.brsw.kr/oidc`에 독립적인 PKCE Public Client로 직접 인증합니다. callback은 `https://qa-test.baroncs.co.kr/auth/callback`이며, Worker가 검증한 claim을 `baron_qa_session` HttpOnly 쿠키에 저장합니다. 브라우저의 `GET /auth/session`은 Q&A 세션에 저장된 작성자 정보를 반환합니다. feedback 서버는 반드시 SSO 세션 또는 토큰을 서버 측에서 검증해야 합니다. +- SSO: Q&A는 홈페이지 로그인 정보를 전달받지 않고, `https://sso.hmac.kr/oidc`에 등록된 독립적인 PKCE Public Client로 직접 인증합니다. callback은 `https://qa-test.baroncs.co.kr/auth/callback`이며, Worker가 검증한 claim을 버전이 지정된 HttpOnly 세션 쿠키에 저장합니다. 브라우저의 `GET /auth/session`은 Q&A 세션에 저장된 작성자 정보를 반환합니다. feedback 서버는 반드시 SSO 세션 또는 토큰을 서버 측에서 검증해야 합니다. - 작성자 식별자: `ssoSubject`/`requesterId`, `userUuid`, `tenantId`/`requesterTenantId`, `tenantIds`, `scope`, `roles`, 이메일·이름·부서·전화번호를 payload에 넣습니다. `requester_id`와 `requester_tenant_id`가 없으면 제출을 차단합니다. -- API: 작성페이지는 같은 Worker의 `POST /api/feedbacks`를 호출합니다. Worker가 `baron_qa_session`을 검증하고, SSO requester 정보와 `ABC_API_KEY` Secret을 추가한 뒤 `POST https://feedback.hmac.kr/api/projects/{projectId}/channels/{channelId}/feedbacks`로 전달합니다. API Key와 내부 ABC 주소는 브라우저에 노출하지 않습니다. +- API: 작성페이지는 같은 Worker의 `POST /api/feedbacks`를 호출합니다. Worker가 Q&A 세션 쿠키를 검증하고, SSO requester 정보와 `ABC_API_KEY` Secret을 추가한 뒤 `POST https://feedback.hmac.kr/api/projects/{projectId}/channels/{channelId}/feedbacks`로 전달합니다. API Key와 내부 ABC 주소는 브라우저에 노출하지 않습니다. - 첨부파일: 작성페이지가 `multipart/form-data`의 반복 `images` 필드로 파일을 Worker에 전달하고, Worker가 검증된 requester 정보와 API Key를 추가해 ABC API로 전달합니다. ABC API가 `qa_cdn` 저장소에 파일을 저장하므로 R2 access key/secret은 정적 페이지에 넣지 않습니다. - 텍스트만 등록할 때는 기존 JSON 요청을 사용하고, 파일이 있을 때만 multipart 요청을 사용합니다. @@ -66,7 +66,7 @@ npx wrangler secret bulk qa-secrets.json --name baron-qa-gateway-test `ABC_API_KEY`에는 프로젝트 전용 ABC API Key를 등록합니다. API Key는 작성페이지 코드나 `egbim/config.js`에 넣지 않습니다. -`AUTH_CLIENT_ID`, `AUTH_AUTHORIZE_URL`, `AUTH_TOKEN_URL`, 선택적인 `AUTH_USERINFO_URL`은 `wrangler.toml`에 실제 SSO 값으로 설정해야 합니다. 현재 Q&A RP는 `https://app.brsw.kr/oidc`를 사용합니다. 이 RP는 PKCE Public Client이므로 `AUTH_CLIENT_SECRET`은 사용하지 않으며, `SESSION_SECRET`만 secret으로 등록합니다. +`AUTH_CLIENT_ID`, `AUTH_AUTHORIZE_URL`, `AUTH_TOKEN_URL`, 선택적인 `AUTH_USERINFO_URL`은 `wrangler.toml`에 실제 SSO 값으로 설정해야 합니다. 현재 Q&A RP는 `https://sso.hmac.kr/oidc`를 사용합니다. 이 RP는 PKCE Public Client이므로 `AUTH_CLIENT_SECRET`은 사용하지 않으며, `SESSION_SECRET`만 secret으로 등록합니다. Worker는 OAuth Authorization Code + PKCE를 사용하고, callback에서 검증한 사용자 claim을 서명된 HttpOnly 세션 쿠키에 저장합니다. 브라우저의 `GET /auth/session`은 정규화된 작성자 정보만 반환합니다. diff --git a/docs/qa-feedback-api-integration-task.md b/docs/qa-feedback-api-integration-task.md index 3c9ef1e..61ce642 100644 --- a/docs/qa-feedback-api-integration-task.md +++ b/docs/qa-feedback-api-integration-task.md @@ -38,7 +38,7 @@ - [ ] `requester_uuid`, `requester_affiliation`, `requester_position`, `requester_grade`의 공개 생성 API 지원 확인 - [x] SSO 세션 저장 및 `/auth/session` 확인 - [x] Worker에 `POST /api/feedbacks` 라우트 추가 -- [x] Worker에서 `baron_qa_session` 검증 +- [x] Worker에서 Q&A 세션 쿠키 검증 - [x] Worker에서 requester 정보 추출 - [x] `requester_id` 매핑: SSO `sub` - [x] `requester_tenant_id` 매핑: SSO `tenant_id` diff --git a/docs/qa-login-to-save-transition.md b/docs/qa-login-to-save-transition.md index 3dfa7c1..7901982 100644 --- a/docs/qa-login-to-save-transition.md +++ b/docs/qa-login-to-save-transition.md @@ -11,12 +11,12 @@ ```mermaid flowchart TD A[바론 홈페이지
EG-BIM Q&A 링크] --> B[Q&A 목록 진입
https://qa-test.baroncs.co.kr/egbim/] - B --> C{Q&A 세션 쿠키
baron_qa_session 유효?} + B --> C{Q&A 세션 쿠키
baron_qa_session_v2 유효?} C -- 예 --> G[정적 목록 페이지 표시] C -- 아니오 --> D[302 /auth/login
return_url 보관] D --> E[Worker가 PKCE 생성
state · verifier · nonce] - E --> F[BRSW OIDC SSO
app.brsw.kr/oidc] + E --> F[BARON-SSO OIDC
sso.hmac.kr/oidc] F --> F1{중앙 SSO 세션 존재?} F1 -- 아니오 --> F2[SSO 로그인 화면] F2 --> F3[최초 동의 화면
필요 시 1회] @@ -26,7 +26,7 @@ flowchart TD I --> J[Worker가 state 검증
PKCE code_verifier 검증] J --> K[Token Endpoint 호출
Public Client · client_secret 없음] K --> L[UserInfo 조회 및 claim 정규화] - L --> M[baron_qa_session 발급
HttpOnly · Secure · SameSite=Lax] + L --> M[baron_qa_session_v2 발급
HttpOnly · Secure · SameSite=Lax] M --> G G --> N[문의 등록 버튼] @@ -59,9 +59,9 @@ flowchart TD | `S0` | 홈페이지 | Q&A 메뉴 클릭 | 외부 Q&A URL로 이동 | `S1` | | `S1` | `/egbim/` | Q&A 세션 유효 | R2의 목록 HTML 제공 | `S5` | | `S2` | `/auth/login` | 세션 없음 | PKCE 상태 생성, SSO로 redirect | `S3` | -| `S3` | `app.brsw.kr/oidc` | SSO 세션 없음 | 최초 로그인 및 동의 | `S4` | +| `S3` | `sso.hmac.kr/oidc` | SSO 세션 없음 | 최초 로그인 및 동의 | `S4` | | `S4` | `/auth/callback` | `code`, `state` 수신 | state/PKCE 검증, token/userinfo 조회 | `S5` | -| `S5` | 목록 또는 작성 페이지 | `baron_qa_session` 유효 | `/auth/session`에서 사용자 확인 | `S6` | +| `S5` | 목록 또는 작성 페이지 | `baron_qa_session_v2` 유효 | `/auth/session`에서 사용자 확인 | `S6` | | `S6` | `write.html` | `userUuid`, `tenantId` 확인 | 작성 폼 입력 대기 | `S7` | | `S7` | 작성 페이지 | 등록 클릭 | `feedbackId` UUID 생성 및 입력 검증 | `S8` | | `S8` | 작성 페이지 | 첨부 있음 | presign → `qa_cdn` 업로드 | `S9` | @@ -83,14 +83,14 @@ https://qa-test.baroncs.co.kr/egbim/ ### B. 중앙 SSO -- Q&A RP는 `https://app.brsw.kr/oidc`를 사용한다. +- Q&A RP는 `https://sso.hmac.kr/oidc`를 사용한다. - 최초 사용자는 SSO 로그인 및 동의 화면을 볼 수 있다. - 같은 중앙 SSO 세션이 있으면 다음 접근부터 로그인 화면 없이 authorization code가 발급된다. - Q&A RP는 PKCE Public Client이므로 client secret을 보내지 않는다. ### C. Q&A 목록 -- Worker가 `baron_qa_session`을 검사한다. +- Worker가 `baron_qa_session_v2`를 검사한다. - 세션이 없으면 `/auth/login?return_url=...`로 이동한다. - 세션이 있으면 R2의 `egbim/index.html`을 제공한다. @@ -159,7 +159,7 @@ apiBaseUrl: '' | SSO 로그인 전 | 로그인 화면 | 중앙 SSO 세션 없음 또는 다른 SSO 환경 | | callback | `invalid_oauth_state` | OAuth cookie 만료, 호스트 변경, state 불일치 | | token 교환 | `oauth_token_exchange_failed` | issuer/endpoint/client ID/PKCE 설정 불일치 | -| 세션 확인 | `authenticated:false` | `baron_qa_session` 없음·만료·`SESSION_SECRET` 불일치 | +| 세션 확인 | `authenticated:false` | `baron_qa_session_v2` 없음·만료·`SESSION_SECRET` 불일치 | | 작성자 확인 | UUID/tenant 오류 | SSO scope 또는 claim mapping 누락 | | 첨부 업로드 | 업로드 실패 | presign API 또는 `qa_cdn` 권한 오류 | | DB 저장 | API 요청 오류 | `apiBaseUrl`, CORS, API 인증, DB envelope 규격 오류 | diff --git a/docs/관리페이지 md 파일/# EG-BIM Q&A 로그인부터 글 저장까지 전이맵.md b/docs/관리페이지 md 파일/# EG-BIM Q&A 로그인부터 글 저장까지 전이맵.md index cae887d..e63bef1 100644 --- a/docs/관리페이지 md 파일/# EG-BIM Q&A 로그인부터 글 저장까지 전이맵.md +++ b/docs/관리페이지 md 파일/# EG-BIM Q&A 로그인부터 글 저장까지 전이맵.md @@ -11,12 +11,12 @@ ```mermaid flowchart TD A[바론 홈페이지
EG-BIM Q&A 링크] --> B[Q&A 목록 진입
https://qa-test.baroncs.co.kr/egbim/] - B --> C{Q&A 세션 쿠키
baron_qa_session 유효?} + B --> C{Q&A 세션 쿠키
baron_qa_session_v2 유효?} C -- 예 --> G[정적 목록 페이지 표시] C -- 아니오 --> D[302 /auth/login
return_url 보관] D --> E[Worker가 PKCE 생성
state · verifier · nonce] - E --> F[BRSW OIDC SSO
app.brsw.kr/oidc] + E --> F[BARON-SSO OIDC
sso.hmac.kr/oidc] F --> F1{중앙 SSO 세션 존재?} F1 -- 아니오 --> F2[SSO 로그인 화면] F2 --> F3[최초 동의 화면
필요 시 1회] @@ -26,7 +26,7 @@ flowchart TD I --> J[Worker가 state 검증
PKCE code_verifier 검증] J --> K[Token Endpoint 호출
Public Client · client_secret 없음] K --> L[UserInfo 조회 및 claim 정규화] - L --> M[baron_qa_session 발급
HttpOnly · Secure · SameSite=Lax] + L --> M[baron_qa_session_v2 발급
HttpOnly · Secure · SameSite=Lax] M --> G G --> N[문의 등록 버튼] @@ -59,9 +59,9 @@ flowchart TD | `S0` | 홈페이지 | Q&A 메뉴 클릭 | 외부 Q&A URL로 이동 | `S1` | | `S1` | `/egbim/` | Q&A 세션 유효 | R2의 목록 HTML 제공 | `S5` | | `S2` | `/auth/login` | 세션 없음 | PKCE 상태 생성, SSO로 redirect | `S3` | -| `S3` | `app.brsw.kr/oidc` | SSO 세션 없음 | 최초 로그인 및 동의 | `S4` | +| `S3` | `sso.hmac.kr/oidc` | SSO 세션 없음 | 최초 로그인 및 동의 | `S4` | | `S4` | `/auth/callback` | `code`, `state` 수신 | state/PKCE 검증, token/userinfo 조회 | `S5` | -| `S5` | 목록 또는 작성 페이지 | `baron_qa_session` 유효 | `/auth/session`에서 사용자 확인 | `S6` | +| `S5` | 목록 또는 작성 페이지 | `baron_qa_session_v2` 유효 | `/auth/session`에서 사용자 확인 | `S6` | | `S6` | `write.html` | `userUuid`, `tenantId` 확인 | 작성 폼 입력 대기 | `S7` | | `S7` | 작성 페이지 | 등록 클릭 | `feedbackId` UUID 생성 및 입력 검증 | `S8` | | `S8` | 작성 페이지 | 첨부 있음 | presign → `qa_cdn` 업로드 | `S9` | @@ -83,14 +83,14 @@ https://qa-test.baroncs.co.kr/egbim/ ### B. 중앙 SSO -- Q&A RP는 `https://app.brsw.kr/oidc`를 사용한다. +- Q&A RP는 `https://sso.hmac.kr/oidc`를 사용한다. - 최초 사용자는 SSO 로그인 및 동의 화면을 볼 수 있다. - 같은 중앙 SSO 세션이 있으면 다음 접근부터 로그인 화면 없이 authorization code가 발급된다. - Q&A RP는 PKCE Public Client이므로 client secret을 보내지 않는다. ### C. Q&A 목록 -- Worker가 `baron_qa_session`을 검사한다. +- Worker가 `baron_qa_session_v2`를 검사한다. - 세션이 없으면 `/auth/login?return_url=...`로 이동한다. - 세션이 있으면 R2의 `egbim/index.html`을 제공한다. @@ -161,7 +161,7 @@ apiBaseUrl: '' | SSO 로그인 전 | 로그인 화면 | 중앙 SSO 세션 없음 또는 다른 SSO 환경 | | callback | `invalid_oauth_state` | OAuth cookie 만료, 호스트 변경, state 불일치 | | token 교환 | `oauth_token_exchange_failed` | issuer/endpoint/client ID/PKCE 설정 불일치 | -| 세션 확인 | `authenticated:false` | `baron_qa_session` 없음·만료·`SESSION_SECRET` 불일치 | +| 세션 확인 | `authenticated:false` | `baron_qa_session_v2` 없음·만료·`SESSION_SECRET` 불일치 | | 작성자 확인 | UUID/tenant 오류 | SSO scope 또는 claim mapping 누락 | | 첨부 업로드 | 업로드 실패 | presign API 또는 `qa_cdn` 권한 오류 | | DB 저장 | API 요청 오류 | `apiBaseUrl`, CORS, API 인증, DB envelope 규격 오류 | diff --git a/wrangler.toml b/wrangler.toml index 110c9e9..e0f9fa5 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -12,12 +12,12 @@ routes = [ AUTH_REDIRECT_URI = "https://qa-test.baroncs.co.kr/auth/callback" AUTH_POST_LOGOUT_REDIRECT_URI = "https://qa-test.baroncs.co.kr/" AUTH_SCOPE = "openid tenants profile email" -AUTH_CLIENT_ID = "e1270f17-e192-4c8c-84b6-54e9698d0f36" -AUTH_AUTHORIZE_URL = "https://app.brsw.kr/oidc/oauth2/auth" -AUTH_TOKEN_URL = "https://app.brsw.kr/oidc/oauth2/token" -AUTH_USERINFO_URL = "https://app.brsw.kr/oidc/userinfo" -SESSION_COOKIE_NAME = "baron_qa_session" -OAUTH_COOKIE_NAME = "baron_qa_oauth" +AUTH_CLIENT_ID = "e16898a7-acd2-420a-a224-cdcd89ff66cd" +AUTH_AUTHORIZE_URL = "https://sso.hmac.kr/oidc/oauth2/auth" +AUTH_TOKEN_URL = "https://sso.hmac.kr/oidc/oauth2/token" +AUTH_USERINFO_URL = "https://sso.hmac.kr/oidc/userinfo" +SESSION_COOKIE_NAME = "baron_qa_session_v2" +OAUTH_COOKIE_NAME = "baron_qa_oauth_v2" SESSION_TTL_SECONDS = "3600" ABC_API_BASE_URL = "https://feedback.hmac.kr" ABC_PROJECT_ID = "01a0ae3f-fcf6-74b5-bdc4-70d942d6ad72"