# OIDC Redirect 매핑 검증 정책

## 목적
- OIDC 로그인/리다이렉트 검증 시, URL 문자열의 기계적 동일성만으로 정상/비정상을 판단하지 않습니다.
- Gateway(Oathkeeper/Nginx) 경유 구조에서 발생하는 Public URL과 Internal URL의 의도된 차이를 정책적으로 허용하되, 매핑의 유효성은 엄격히 검증합니다.

## 적용 범위
- UserFront, AdminFront, DevFront의 로그인/콜백 경로
- Ory Stack(Hydra/Kratos/Oathkeeper) 설정
- `compose.ory.yaml`, `docker/compose.ory.yaml`, `docker/staging_pull_compose.template.yaml`
- `gateway/nginx.conf`, `deploy/templates/gateway/nginx.conf`, `docker/ory/oathkeeper/rules*.json`
- `Makefile` 기반 사전 검증/스모크 검증 단계

## 핵심 원칙
1. URL 직접 일치(`direct_match`)와 게이트웨이 매핑 일치(`mapped_match`)를 구분합니다.
2. Public URL과 Internal URL이 다르더라도, `Public -> Gateway/Oathkeeper -> Internal` 경로가 검증되면 정상으로 간주합니다.
3. 매핑 체인이 없거나 규칙이 누락된 경우는 실패(`unmapped_fail`)로 간주합니다.

## 용어 정의
- Public URL: 브라우저에서 접근하는 URL. 예: `https://sso-test.hmac.kr/oidc/oauth2/auth`
- Internal URL: 컨테이너 내부 통신 URL. 예: `http://hydra:4444/oauth2/auth`
- Mapping Chain: Public 요청이 Gateway/Oathkeeper 규칙을 통해 Internal URL로 전달되는 경로

## 판정 규칙
1. `direct_match`
- 프론트가 생성한 `redirect_uri`/`authority`와 실제 등록/설정 URL이 동일 레이어에서 직접 일치
- 예: 로컬 개발에서 모두 `http://localhost:*` 기준

2. `mapped_match`
- Public URL과 Internal URL이 다르지만, 아래가 모두 성립
- Gateway 라우팅 규칙 존재: `/oidc` prefix를 제거하지 않고 Oathkeeper로 전달
- Oathkeeper `match`와 `upstream` 규칙 존재: `/oidc/*` rule이 `strip_path=/oidc`로 Hydra에 전달
- 최종 업스트림이 기대 서비스(Hydra/Kratos)로 연결

3. `unmapped_fail`
- Public/Internal 불일치가 있는데 매핑 규칙이 없거나 누락
- callback/return URL이 등록되지 않았거나 경로 규약 불일치
- 환경 변수는 존재하나 실제 compose/rules 반영이 누락

## 검증 항목
1. 정적 검증 (`make validate-auth-config`)
- `USERFRONT_URL`, `OATHKEEPER_PUBLIC_URL`, `HYDRA_PUBLIC_URL`, `KRATOS_BROWSER_URL` 정합성
- `ADMINFRONT_CALLBACK_URLS`, `DEVFRONT_CALLBACK_URLS` URL 유효성/중복/경로 규약
- Gateway `/oidc`, `/auth` 라우팅 규칙 존재 여부
- Oathkeeper `rules*.json`의 Hydra/Kratos 매핑 규칙 존재 여부
- staging pull/deploy template의 Oathkeeper entrypoint 사용 여부
- `KRATOS_ALLOWED_RETURN_URLS_JSON`에 공개 도메인, locale path, callback/return path가 포함되는지 여부

2. 런타임 검증 (`make verify-oidc-config`)
- OIDC Discovery endpoint 조회 가능 여부
- Hydra 등록 client(`adminfront`, `devfront`)의 `redirect_uris` 확인
- 필요 시 Gateway 경유 endpoint probe로 매핑 체인 확인

## 경로 규약
- DevFront callback: `/auth/callback`
- AdminFront callback: `/auth/callback`
- OrgFront callback: `/auth/callback`
- UserFront OIDC 진입점: `/oidc/*` (Gateway 경유)
- locale return path: `/ko`, `/en`, `/ko/auth/callback`, `/en/auth/callback`

## `/oidc` 책임 경계
- Gateway는 `/oidc` prefix를 보존합니다.
- Oathkeeper는 `/oidc/.well-known/*`, `/oidc/oauth2/*`, `/oidc/userinfo` rule에서 `strip_path=/oidc`를 적용합니다.
- Hydra는 prefix가 제거된 내부 경로(`/.well-known/*`, `/oauth2/*`, `/userinfo`)를 받습니다.
- 따라서 gateway template이나 staging pull compose에서 `rewrite ^/oidc`가 다시 들어가면 dev/stage/prod 간 책임 경계가 달라지므로 실패로 간주합니다.

## Oathkeeper rules 선택 정책
- Oathkeeper는 직접 `command: serve proxy ...`로 시작하지 않고 `/etc/config/oathkeeper/entrypoint.sh`를 통해 시작합니다.
- entrypoint는 `APP_ENV`에 따라 다음 파일을 선택하고 `/tmp/oathkeeper/rules.active.json`으로 복사합니다.
  - `stage|staging`: `rules.stage.json`
  - `production|prod`: `rules.prod.json`
  - 그 외: `rules.json`
- `oathkeeper.yml`은 `file:///tmp/oathkeeper/rules.active.json`만 읽습니다.

## Kratos allowed return URL 정책
- stage/prod에서는 `KRATOS_ALLOWED_RETURN_URLS_JSON`을 명시하는 것을 우선합니다.
- 최소 포함 대상:
  - `KRATOS_UI_URL`, `KRATOS_UI_URL/`
  - `USERFRONT_URL`, `USERFRONT_URL/`
  - `USERFRONT_URL/ko`, `USERFRONT_URL/ko/`
  - `USERFRONT_URL/en`, `USERFRONT_URL/en/`
  - `USERFRONT_URL/auth/callback`
  - `USERFRONT_URL/ko/auth/callback`
  - `USERFRONT_URL/en/auth/callback`
  - `ADMINFRONT_CALLBACK_URLS`, `DEVFRONT_CALLBACK_URLS`, `ORGFRONT_CALLBACK_URLS`
- private IP, legacy domain, comma-space가 포함된 URI 항목은 stage/prod 기본값으로 두지 않습니다.

## 운영 지침
1. 환경별 URL은 동일할 필요가 없고, 매핑 체인이 검증 가능해야 합니다.
2. `localhost` 하드코딩은 로컬 전용 예외로만 허용하며, 스테이징/운영은 env 기반으로 주입합니다.
3. 신규 도메인/경로 추가 시, 프론트 설정과 Ory/Gateway 규칙을 반드시 동시에 변경하고 검증 결과를 이슈/PR에 첨부합니다.

## 관련 이슈
- #262
- #269
- #271
- #272
- #274
- #276
- #710
