크라우니메일(mail.crowny.org:9610) — 크라우니 통합인증 정본 IdP 승격
개요
오너 확정에 따라 정본 계정 = 메일 계정(mail.crowny.org:9610)으로 삼고, 메일 서버를 크라우니 통합 인증의 IdP(Identity Provider)로 승격시켰다. SSOT는
/Users/ef/crowny-mail/docs/크라우니-통합인증-IdP스펙.md §2·§3·§6.
무엇을 했나
- 토큰 규격(v1)
id.exp.ver.sig — sig = SHA256(시크릿|id|exp|ver|시크릿) 봉투(envelope) MAC. /Users/ef/crowny-services/서비스서버.한선의 717행 세션서명/757행 인증확정/926행 시크릿초기화를 참조 구현으로 삼아 동형 이식하되, 함수명은 전부 IdP 접두로 격리(IdP시크릿초기화/IdP서명/IdP토큰발급/IdP토큰검증/IdP세션버전/IdP세션버전올림/IdP베어러추출/IdP아이디유효/IdP부트스트랩키확인/_파일있나).
- 시크릿:
/Users/ef/crowny-data/auth/.idp-secret (64hex, chmod 600, 부팅 1회 생성·재기동 간 안정).
- 세션버전 저장소:
/Users/ef/crowny-data/auth/세션버전.psv (id|ver 라인).
- 라우트:
-
POST /api/auth/login — 응답에
idpToken 필드 추가(기존
token/
email/
name/
role 그대로 유지).
-
POST /api/auth/verify — 신규·무인증,
{token} 바디 또는
Authorization: Bearer →
{ok,id,email,name,role}/401.
-
GET /api/auth/jwks — 신규·무인증, 규격 공표(시크릿 비노출).
- 기존
세션검증 게이트 앞에 IdP Bearer 토큰 폴백 추가(불투명 세션 우선 → 실패 시 IdP 토큰).
-
POST /api/auth/logout-all — 신규, 세션 또는 IdP 토큰으로 오너 식별 후
IdP세션버전올림 → 기존 발급 토큰 전부 무효화.
-
POST /api/auth/bootstrap-reset — 신규,
127.0.0.1 요청만(
_루프백허용가 재사용) +
.bootstrap-key 파일 정확 일치 시에만 동작, 비번 변경은 기존
_비번변경적용및기록 함수 호출로만 원장 기록(직접 원장 편집 없음).
- VM 함정 회피: 이 파일은
파일존재()가 항상 -1(주석에 기 명시된 함정)이라, 기존 코드 관례(_DKIM키있나)를 따라 체계("test -s ... && printf 1 || printf 0") 패턴(_파일있나)으로 존재 확인을 통일.
컴파일 · 재기동 · 검증 (실측)
hanseonc_high STRICT 컴파일 0경고, 66536 큐브 생성.
- LaunchAgent
com.crowny.mail(KeepAlive=true) 기존 프로세스 kill → 자동 재기동 확인(launchctl 개입 없이 자가치유).
.bootstrap-key 생성(openssl rand -hex 16) → kps/kps1234 설정 성공 → 사용 후 즉시 삭제.
- 게이트 1~5 전부 실측 PASS:
1. STRICT 0경고 + 재기동 후 기존 웹 로그인 무중단(admin/crowny2026! 등 기존 계정 회귀 확인)
2. bootstrap-reset → kps/kps1234 로그인 성공 + idpToken 발급 확인
3. 발급 토큰
/api/auth/verify →
{"ok":1,"id":"kps",...}
4. 위조 sig(문자 추가) → 401, 위조 exp(=1)+ver(=1) → 401 각각 실측
5.
logout-all 후 구 토큰
/api/auth/verify → 401, 재로그인 시 신규 토큰(ver 증가) 정상 발급
- 추가 회귀: IdP토큰만으로(X-Session 없이 Authorization: Bearer만) 보호 라우트
/api/mail/inbox 200 확인. 무토큰 요청은 401.
관련 파일
/Users/ef/crowny-mail/크라우니메일서버.한선 (수정 대상, IdP 함수군 + 라우트 3종 신규 + 로그인/세션게이트 변경)
/Users/ef/crowny-mail/크라우니메일서버.한선.bak-IdP승격-20260730 (작업 전 백업)
/Users/ef/crowny-mail/크라우니메일서버.toau (재컴파일 산출물)
/Users/ef/crowny-mail/docs/크라우니-통합인증-IdP스펙.md (SSOT)
/Users/ef/crowny-data/auth/.idp-secret (신규, chmod 600)
/Users/ef/crowny-data/auth/세션버전.psv (신규)
/Users/ef/Library/LaunchAgents/com.crowny.mail.plist (읽기만, 변경 없음)
잔여 이슈
- §4 연동 순서(클라우드→텔레→DEX→넥서스→트레이딩→집사회→메신저→ERP/견적)는 이번 작업 범위 밖 — 각 서비스별 IdP 분기는 후속 세션 과제.
- §5 블록체인 앵커(클라우드
/api/anchor로 원장 행 SHA256 앵커)는 미착수. 현재는 메일 원장(append-only)에만 1차 기록.
_비번변경적용및기록은 이메일 기준 조회(사용자찾기)라서 bootstrap-reset이 내부적으로 id→email 변환을 거친다 — 다계정 동시 충돌은 낮은 위험이나 미검증.
- 기존 세션 만료 로직(
세션생성의 현재시간()+86400000)은 현재시간이 초 단위 별칭(OP_TIME_NOW)이라 사실상 만료가 매우 먼 미래로 잡히는 기존 버그를 이번 작업에서 발견했으나, 스코프 밖이라 손대지 않음(불투명 세션 토큰 자체 만료 로직, IdP 토큰과는 무관) — 별도 티켓 권장.
새로 발견한 한선씨 VM 함정 (다른 세션 참고용)
현재시각()과 현재시간()은 서로 다른 이름이지만 완전히 동일한 opcode(hanseonc_high.c:1246, 현재시간은 OP_TIME_NOW의 별칭)다. 둘 다 초 단위 유닉스 타임을 반환하며 밀리초 버전은 존재하지 않는다. "현재시간=ms, 현재시각=sec"로 추정하고 밀리초 연산(+86400000)을 하면 만료 시각이 의도한 하루가 아니라 수백~수천 년 뒤로 밀려나는 조용한 버그가 생긴다(크라우니메일 기존 세션생성 함수가 이 패턴).