Skip to content

feat: 프로필 수정 본인 확인 가드 추가 및 통합 테스트 수정#219

Merged
dstle merged 3 commits into
devfrom
feature/149-profile-update-self-guard
Jun 30, 2026
Merged

feat: 프로필 수정 본인 확인 가드 추가 및 통합 테스트 수정#219
dstle merged 3 commits into
devfrom
feature/149-profile-update-self-guard

Conversation

@dstle

@dstle dstle commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

관련 이슈

작업 내용

  • 프로필 수정 API 본인 확인(인가) 가드 추가
  • 사용자 단건 조회 API 인증 확인
  • getUser_notFound 통합 테스트 404 + 응답 바디 검증 강화
  • CSRF 토큰을 헤더에 자동 포함하도록 Swagger yml 설정 추가

변경 사항

프로필 수정 본인 확인 (#149)

  • UserService.updatevalidateOwner(현재 사용자 == 대상 userId) → 불일치 시 403
  • UserForbiddenException(403) 추가, @AuthenticationPrincipal로 인증 주체 식별
  • SecurityConfig: PATCH /api/users/* 인증 필요

단건 조회 IDOR (#128 이슈 2)

  • GET /api/users/* 인증 필요 → 비로그인 401
  • 응답은 명세(UserDto)대로 email/role/locked 포함 전체 공개 유지 (필드 마스킹 X)
  • getById 존재 확인(404)은 기존 로직 유지

테스트 강화 (#129)

  • getUser_notFound 404 + exceptionType/message 검증 (slice·통합)
  • getUser 비인증 401 케이스 추가, invalid-uuid 500 확정 검사
  • FollowControllerIntegrationTest authentication() 주입 방식으로 복구

Swagger CSRF (#217)

  • springdoc.swagger-ui.csrf.enabled=true → Swagger UI가 XSRF-TOKEN 쿠키를 X-XSRF-TOKEN 헤더로 자동 주입

테스트 내용

  • 테스트 코드 작성
  • 로컬 테스트 완료
  • API 테스트 완료
  • 기타 테스트 완료

체크리스트

  • 코드 컨벤션을 지켰습니다.
  • 불필요한 코드를 제거했습니다.
  • 주석이 필요한 부분에 추가했습니다.
  • 관련 문서를 수정했습니다.
  • 리뷰어가 이해하기 쉽도록 작성했습니다.

리뷰 포인트

  • 중점적으로 봐줬으면 하는 부분을 작성해주세요.

스크린샷 / 참고 자료

  • 필요한 경우 첨부해주세요.

🔗 관련 이슈

  • close #149
  • close #128
  • close #129
  • close #217

📝 작업 내용

이 PR은 사용자 리소스에 대한 보안 정책(인가/인증) 강제와 API 에러 계약을 테스트에서 더 정확히 고정하기 위해 진행됐습니다.
기존에는 프로필 수정 시 “요청자가 본인인지” 검증이 수정 로직 진입 전에 확실히 강제되지 않았고, 사용자 단건 조회도 인증 없이 접근될 수 있어 보안 경계가 느슨했습니다. 또한 통합 테스트가 응답 상태/바디를 느슨하게 검증해 실제 API 계약과 어긋날 여지가 있었습니다.

주요 변경사항

  1. 프로필 수정(PATCH /api/users/{userId})에 본인 확인 인가 가드 추가

    • UserController에서 @AuthenticationPrincipal로 인증 주체의 ID를 주입하고, UserService.update로 전달 인자를 확장했습니다.
    • UserService.update 내부에서 validateOwner(currentUserId, userId)를 호출해 **요청자와 대상 userId 불일치 시 UserForbiddenException(403)**을 던지도록 변경했습니다.
    • 예외 메시지/형태는 예외 생성 시 requesterId, userId를 포함하도록 고정했습니다.
    • (설계 선택) 검증을 서비스의 실제 수정 흐름 근처에서 강제해 이미지 업로드 여부 등과 무관하게 동일한 보안 규칙이 적용되도록 했습니다.
  2. 사용자 단건 조회(GET /api/users/{userId}) 인증 요구 강화

    • SecurityConfig에서 GET /api/users/*PATCH /api/users/*엔드포인트별로 authenticated() 처리하도록 조정했습니다(단, /api/users 컬렉션은 permitAll 유지).
    • 그 결과 통합 테스트에서도 비인증 요청이 **401 Unauthorized**로 처리되는 케이스를 추가/정비했습니다.
    • 응답 바디는 기존과 동일하게 email, role, locked를 포함한 공개 형태를 유지했습니다.
  3. 통합 테스트/예외 응답 계약을 명세 수준으로 정밀화

    • getUser_notFound는 단순 상태 코드 범위 대신 정확한 404 + exceptionType + message 응답 바디를 검증하도록 강화했습니다.
    • getUser비인증 401 케이스와 **invalid-uuid 케이스의 현재 기대값 검증(500)**을 추가했습니다.
    • FollowControllerIntegrationTest는 인증 주입 방식을 복원(authentication() post-processor + csrf() 반영)해 실제 시큐리티 필터 동작에 맞게 실행되도록 했습니다.
    • Swagger UI에서 CSRF 토큰이 헤더에 자동 주입되도록 springdoc.swagger-ui.csrf.enabled=true를 설정했습니다.

📌 리뷰 포인트 / 트레이드오프

  • SecurityConfig는 전역 규칙(anyRequest().permitAll())이 남아있는 상태에서 /api/users/* 등 주요 엔드포인트를 명시적으로 인증 처리하는 방식으로 맞춰져 있습니다. 다른 리소스까지 의도대로 완전히 닫히는지 여부는 범위 밖이며(측정하지 않음), 이번 PR은 사용자 관련 정책과 테스트 신뢰성에 집중했습니다.

📊 변경 효과 요약 (가능한 경우에만)

  • 통합 테스트 정비:
    • UserControllerIntegrationTest: +54/-19
    • UserControllerTest: +24/-11
    • FollowControllerIntegrationTest: +200/-208
  • 설정/계약 관련:
    • application.yml: +5/-0 (springdoc.swagger-ui.csrf.enabled=true)
    • application-test.yml: +6/-0 (테스트용 JWT 설정 추가)
  • 보안/서비스 계층 변경:
    • UserService: 업데이트 시그니처 변경 및 본인검증 로직 추가
    • UserForbiddenException: 신규 추가 (403)
      </final_summary>

dstle added 2 commits June 30, 2026 11:29
# Conflicts:
#	src/test/java/com/codeit/team5/mopl/user/controller/UserControllerIntegrationTest.java
#	src/test/java/com/codeit/team5/mopl/user/controller/UserControllerTest.java
#	src/test/java/com/codeit/team5/mopl/user/service/UserServiceTest.java
@dstle dstle self-assigned this Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7ac51fcb-bbd6-47f9-b35a-c3ba70179af6

📥 Commits

Reviewing files that changed from the base of the PR and between 3b64e94 and 6f8d0bf.

📒 Files selected for processing (4)
  • src/test/java/com/codeit/team5/mopl/auth/controller/AuthControllerIntegrationTest.java
  • src/test/java/com/codeit/team5/mopl/user/controller/UserControllerIntegrationTest.java
  • src/test/java/com/codeit/team5/mopl/user/controller/UserControllerTest.java
  • src/test/resources/application-test.yml

📝 Walkthrough

Walkthrough

사용자 프로필 수정 API에 본인 확인 인가 가드가 추가되었습니다. UserController는 인증 주체를 주입받아 UserService.update에 전달하고, 서비스는 요청자 ID와 대상 사용자 ID를 비교해 불일치 시 UserForbiddenException을 반환합니다. SecurityConfig/api/users/*의 PATCH/GET 요청에 인증을 요구하도록 갱신됐고, UserApi 시그니처도 이에 맞게 바뀌었습니다. 관련 테스트는 인증 주입 방식과 401/403/404 검증으로 정리됐고, Follow 통합 테스트는 인증 주입과 CSRF 반영 방식으로 바뀌었습니다. AuthController 테스트와 테스트용 JWT 설정도 함께 수정됐습니다.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 대부분 맞지만 #129에서 invalidUuid를 400이 아니라 500으로 검증하고, 에러 필드도 이슈의 exceptionName과 다릅니다. getUser_notFound는 404와 exceptionName/message를 검증하고, invalidUuid는 400으로 고쳐 명세에 맞추세요.
Out of Scope Changes check ⚠️ Warning AuthController JWT 테스트 설정 이동과 FollowController 인증 주입 복구는 링크된 이슈의 직접 요구 범위를 벗어납니다. 이 변경은 별도 PR로 분리하거나, #128/#149/#129/#217 해결에 필수인 근거를 description에 추가하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 프로필 수정 본인 확인 가드와 통합 테스트 수정이라는 핵심 변경을 잘 요약합니다.
Description check ✅ Passed 필수 섹션과 이슈/작업/테스트/체크리스트가 대부분 채워져 있어 템플릿 요구를 충족합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/149-profile-update-self-guard

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/codeit/team5/mopl/config/SecurityConfig.java`:
- Around line 60-61: SecurityConfig still leaves a global permit-all fallback,
so any /api/** route not explicitly matched remains anonymously accessible.
Update the HttpSecurity rules in SecurityConfig to remove the final
anyRequest().permitAll() and replace it with a stricter default such as
anyRequest().denyAll() or anyRequest().authenticated(), while keeping the
existing requestMatchers for /api/users/* intact. Make sure the fallback matches
the linked issue goal of eliminating global public access and only allows routes
that are explicitly intended to be open.

In `@src/main/java/com/codeit/team5/mopl/user/controller/UserController.java`:
- Around line 67-68: 이미지 파싱이 userService.update 호출 전에 먼저 실행되어 비소유자 요청에도
MultipartFiles.toImageResource(image) 검증과 getBytes()가 선행되는 문제를 수정하세요.
UserController의 update 흐름에서 userDetails.getId(), userId, request,
MultipartFiles.toImageResource(image) 호출 순서를 조정해 소유자 확인이 먼저 일어나도록 하거나, 이미지 변환을
지연 평가하도록 update API를 변경해 validateOwner가 먼저 실행되게 하세요. UserController.update,
userService.update, validateOwner, MultipartFiles.toImageResource를 기준으로 위치를 찾아
반영하면 됩니다.

In
`@src/test/java/com/codeit/team5/mopl/follow/controller/FollowControllerIntegrationTest.java`:
- Around line 37-40: FollowControllerIntegrationTest currently relies on
SpringBootTest with SecurityConfig, JwtAuthenticationFilter, and JwtProperties,
but the test profile lacks the required jwt.* configuration. Add the missing JWT
test settings for this test by moving the common inline values into
application-test.yml so JwtProperties can bind successfully and the integration
context starts consistently.

In
`@src/test/java/com/codeit/team5/mopl/user/controller/UserControllerIntegrationTest.java`:
- Around line 233-236: The invalid UUID integration test is asserting the wrong
contract by expecting a 500 response in UserControllerIntegrationTest. Update
the expectation in the test that exercises get("/api/users/{userId}",
"invalid-uuid") to validate 400 Bad Request instead, and if the current runtime
still returns 500, fix the exception-to-response mapping in the
controller/advice path used by UserController so path-variable UUID parsing
failures are translated to a client error rather than a server error.

In `@src/test/java/com/codeit/team5/mopl/user/controller/UserControllerTest.java`:
- Line 345: The updateUser test currently uses any() for both the authenticated
principal id and the target userId, so it can’t detect swapped or duplicated IDs
in UserControllerTest. Update the test around updateUser to use two different
UUIDs for the AuthenticationPrincipal and path parameter, then verify the
userService.update call with explicit argument matching so the first parameter
is the principal id and the target id is the path userId. Apply the same
tightening to the related successful-path assertions in the nearby updateUser
test cases that currently mirror this pattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6214fb78-0334-48a6-995a-f8faddf62d3d

📥 Commits

Reviewing files that changed from the base of the PR and between 85b1d01 and 3b64e94.

📒 Files selected for processing (12)
  • gradlew
  • src/main/java/com/codeit/team5/mopl/config/SecurityConfig.java
  • src/main/java/com/codeit/team5/mopl/follow/entity/Follow.java
  • src/main/java/com/codeit/team5/mopl/user/controller/UserController.java
  • src/main/java/com/codeit/team5/mopl/user/controller/api/UserApi.java
  • src/main/java/com/codeit/team5/mopl/user/exception/UserForbiddenException.java
  • src/main/java/com/codeit/team5/mopl/user/service/UserService.java
  • src/main/resources/application.yml
  • src/test/java/com/codeit/team5/mopl/follow/controller/FollowControllerIntegrationTest.java
  • src/test/java/com/codeit/team5/mopl/user/controller/UserControllerIntegrationTest.java
  • src/test/java/com/codeit/team5/mopl/user/controller/UserControllerTest.java
  • src/test/java/com/codeit/team5/mopl/user/service/UserServiceTest.java

Comment thread src/main/java/com/codeit/team5/mopl/config/SecurityConfig.java
Comment thread src/test/java/com/codeit/team5/mopl/user/controller/UserControllerTest.java Outdated
@dstle dstle requested a review from shong9124 June 30, 2026 04:34

@shong9124 shong9124 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인증쪽 반영된 거 확인했습니다! 팔로우쪽 테스트도 활성화해주신 것도 확인했습니다~
코드 이상 없는 것 같아서 승인합니다!
고생하셨어요!!

@dstle dstle merged commit d880462 into dev Jun 30, 2026
2 checks passed
@dstle dstle deleted the feature/149-profile-update-self-guard branch June 30, 2026 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment