Skip to content

FIX : 카카오 가입 완료 복구와 역할 권한 상승 차단, UserService 테스트 - #104

Merged
RosieOh merged 1 commit into
mainfrom
test/user-service-coverage
Sep 22, 2026
Merged

RosieOh merged 1 commit into
mainfrom
test/user-service-coverage

Conversation

@RosieOh

@RosieOh RosieOh commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

🏫 관련 이슈

Closes #93
Closes #103

🏫 PR 타입

  • 기능 추가
  • 기능 수정
  • 기능 삭제
  • 버그 수정
  • 의존성, 환경 변수, 빌드 관련 코드 업데이트

🏫 반영 브랜치

test/user-service-coverage -> main

🏫 변경 사항

#93(UserService 커버리지 0.7%)을 하러 들어갔다가, 테스트를 쓰면서 카카오 가입 완료 경로에서 P0 를 찾았다 (#103).

1. 카카오 신규 가입이 전부 막혀 있었다 ⭐

카카오 로그인 → 가입 미완료 사용자에게도 토큰 발급
      ↓
프런트가 그 토큰으로 POST /auth/kakao/complete-registration
      ↓
JWT 필터: path.startsWith("/auth/kakao") → 통째로 건너뜀   ← 토큰 미해석
      ↓
컨트롤러 requireCurrentUserEmail() → 401

통합 테스트로 재현했다. 유효한 토큰을 들고도 expected: 200 but was: 401.
카카오로 처음 들어온 사람은 누구도 가입을 끝낼 수 없었다.

→ 필터 예외를 /auth/kakao/login, /auth/kakao/login-url 로 좁히고, 가입 완료를 authenticated() 로.

2. 역할을 클라이언트가 정했다 — 누구나 관리자 ⭐

userRole = UserRole.valueOf(role);   // 요청 본문 그대로
// "가능한 역할: PARENT, CAREGIVER, ADMIN, GUEST"  ← 오류 메시지가 친절하게 알려줌

이메일 가입의 #82 와 같은 결함이다.

이 두 결함은 하나만 고치면 더 나빠진다. 지금까지 2번이 드러나지 않은 건 1번이 흐름을 막고
있었기 때문이다. 1번만 고쳤다면 카카오 로그인 한 번으로 관리자가 되는 경로가 열렸을 것이다.

→ 스스로 고를 수 있는 역할을 허용 목록(PARENT, CAREGIVER)으로 제한.
금지 목록이 아니라서 나중에 특권 역할이 추가돼도 기본으로 막힌다.
프런트 가입 화면은 role: 'PARENT' 고정이라 깨지지 않는다.

3. Boolean 언박싱 NPE 3곳

registrationCompleted / isActive 가 Boolean 인데 !x.getRegistrationCompleted(),
x.getIsActive() && 로 언박싱했다. null 이면 카카오 로그인(AuthServiceImpl)·가입 완료·계정 복구가 500.

4. UserService 테스트 (#93)

이전 이후
UserService 라인 커버리지 0.7% (2/283) 95.8% (275/287)
전체 라인 커버리지 34.9% 37.8%
전체 ratchet 0.30 0.35
CLASS 60% 규칙 — UserService 추가

0.7% 였던 동안 이 클래스에서 P0 가 세 번 나왔다 — #82 가입 role, #83 역할 변경 노출, 그리고 이번 카카오 role.

@PreAuthorize 는 스프링 프록시가 적용해서 단위 테스트 범위 밖이다. 그 계약은
AccessControlContractTest / EndpointAuthorizationCoverageTest 가 맡는다.

🏫 테스트 결과

460 tests, 0 failures   (기존 411 → +49)
BUILD SUCCESSFUL (jacocoTestCoverageVerification 포함, 올린 게이트 통과)
신규 테스트 고정하는 계약
KakaoRegistrationCompletionTest (6, 통합) 토큰으로 가입 완료 200 / ADMIN·GUEST 400 이고 역할·완료 여부 불변 / 토큰 없으면 401 / 카카오 로그인은 여전히 공개
UserServiceTest (43) 가입 완료 역할 허용목록, 이미 완료한 사용자 재실행 거부(역할 우회로 차단), 비밀번호 변경, 계정 상태·소프트 삭제·복구, 역할 변경, 조회·검색, DTO 에 비밀번호 해시 미포함, 카카오 API 응답 처리

EndpointAuthorizationCoverageTest 의 공개 목록에서 가입 완료를 뺐다. 그 자리에 "예전에 공개로 적혀 있었고
그래서 흐름 전체가 401 이었다"
는 주석을 남겼다 — 누가 다시 넣지 않도록.

🏫 To Reviewer

  • CAREGIVER(보육사)를 자가 선택 가능으로 뒀다. 현재 코드에서 특권이 있는 역할은 ADMIN 뿐이라
    (hasRole 전수 확인) 안전하지만, 보육사에 별도 권한을 붙일 계획이 있다면 그 전에 허용 목록에서 빼야 한다.
  • AuthServiceImpl 커버리지가 1% 다. 카카오 로그인 본체인데, 이번에 언박싱 한 줄만 고치고
    테스트는 붙이지 않았다. 계정 연결(같은 이메일의 기존 계정에 카카오를 붙이는 로직)이 들어 있어
    다음으로 봐야 할 곳이다.
  • getKakaoUserInfo 가 카카오 액세스 토큰 앞 20자를 INFO 로그에 남긴다. 이번 범위에서는 손대지 않았다.

UserService 테스트를 쓰다가 카카오 가입 완료 경로에서 결함 두 개를 찾았다.
하나만 고치면 더 나빠지는 구조라 함께 고친다.

1) 카카오 신규 가입이 전부 막혀 있었다.

   카카오 로그인은 가입 미완료 사용자에게도 토큰을 주고, 프런트는 그 토큰으로
   /auth/kakao/complete-registration 을 부른다. 그런데 JWT 필터가
   path.startsWith("/auth/kakao") 로 통째로 건너뛰어 토큰이 해석되지 않았고,
   컨트롤러가 현재 사용자를 찾다가 401 을 냈다. 통합 테스트로 재현했다
   (유효한 토큰으로 호출해도 expected 200 but was 401).

   필터 예외를 /auth/kakao/login, /auth/kakao/login-url 로 좁히고,
   SecurityConfig 에서 가입 완료를 authenticated() 로 바꿨다.

2) 역할을 클라이언트가 정했다.

   요청 본문의 role 을 UserRole.valueOf 로 그대로 저장했고, 오류 메시지가
   "가능한 역할: PARENT, CAREGIVER, ADMIN, GUEST" 라고 알려주기까지 했다.
   {"role":"ADMIN"} 이면 그 자리에서 관리자다. 이메일 가입의 #82 와 같다.

   지금까지 드러나지 않은 건 1번이 흐름을 막고 있었기 때문이다. 1번만 고치면 그대로 열린다.
   스스로 고를 수 있는 역할을 허용 목록(PARENT, CAREGIVER)으로 제한했다. 금지 목록이
   아니라 허용 목록이라, 나중에 특권 역할이 추가돼도 기본으로 막힌다.
   프런트 가입 화면은 PARENT 로 고정해 보내므로 깨지지 않는다.

3) Boolean 언박싱 3곳을 null 안전하게 했다.

   registrationCompleted / isActive 가 Boolean 인데 !x.get...(), x.get...() && 로 언박싱했다.
   null 이면 카카오 로그인(AuthServiceImpl), 가입 완료, 계정 복구가 NPE 로 500 이었다.

UserService 테스트 (#93)

  라인 커버리지 0.7% → 95.8%. 0.7% 였던 동안 이 클래스에서 P0 가 세 번 나왔다
  (#82 가입 role, #83 역할 변경 노출, 그리고 이번 카카오 role).
  build.gradle 의 CLASS 60% 규칙에 UserService 를 넣고, 전체 ratchet 을 0.30 → 0.35 로 올렸다.

  @PreAuthorize 는 스프링 프록시가 적용하므로 단위 테스트 범위 밖이다. 그 계약은
  접근제어 통합 테스트가 맡는다.

460 tests, 0 failures. 전체 라인 커버리지 34.9% → 37.8%.
@RosieOh
RosieOh merged commit a6b94e1 into main Sep 22, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant