From e9a3fc82e5f7be587a04d6b4c4a77b20f8f4c3cf Mon Sep 17 00:00:00 2001 From: ByungCheol Date: Sat, 6 Jun 2026 14:14:15 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20verify-password=C2=B7profile=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=EC=85=89=ED=84=B0=20=EB=B3=B4=ED=98=B8=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EB=88=84=EB=9D=BD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - WebConfig authInterceptor 경로에 /api/auth/verify-password, /api/auth/profile 추가 (누락 시 CURRENT_MEMBER 미설정 → 로그인 사용자도 NPE 500) - WebConfigTest: 인증 필수 auth 엔드포인트 보호 경로 등록 회귀 가드 Co-Authored-By: Claude Opus 4.8 --- .../com/sb/web/common/config/WebConfig.java | 1 + .../sb/web/common/config/WebConfigTest.java | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/test/java/com/sb/web/common/config/WebConfigTest.java diff --git a/src/main/java/com/sb/web/common/config/WebConfig.java b/src/main/java/com/sb/web/common/config/WebConfig.java index f179ada..f36fc5a 100644 --- a/src/main/java/com/sb/web/common/config/WebConfig.java +++ b/src/main/java/com/sb/web/common/config/WebConfig.java @@ -24,6 +24,7 @@ public class WebConfig implements WebMvcConfigurer { // 인증: 로그인 필요한 경로 (관리자 경로 포함 — SessionUser 세팅용으로 먼저 실행) registry.addInterceptor(authInterceptor) .addPathPatterns("/api/auth/me", "/api/auth/logout", "/api/auth/password", + "/api/auth/verify-password", "/api/auth/profile", "/api/board/**", "/api/admin/**", "/api/account/**"); // 인가: 관리자 전용 경로 (authInterceptor 다음에 실행되어 role 검사) registry.addInterceptor(adminInterceptor) diff --git a/src/test/java/com/sb/web/common/config/WebConfigTest.java b/src/test/java/com/sb/web/common/config/WebConfigTest.java new file mode 100644 index 0000000..bf62607 --- /dev/null +++ b/src/test/java/com/sb/web/common/config/WebConfigTest.java @@ -0,0 +1,51 @@ +package com.sb.web.common.config; + +import com.sb.web.auth.web.AdminInterceptor; +import com.sb.web.auth.web.AuthInterceptor; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.springframework.web.servlet.config.annotation.InterceptorRegistration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * 인터셉터 보호 경로 등록 회귀 가드. + * CURRENT_MEMBER 를 쓰는 인증 필수 엔드포인트가 authInterceptor 경로에 빠지면 + * 인터셉터가 동작하지 않아 로그인 사용자도 NPE(500)가 난다. (verify-password/profile 누락 사례) + */ +class WebConfigTest { + + @Test + @DisplayName("인증 필수 auth 엔드포인트가 모두 보호 경로에 등록된다") + void protectsAuthEndpoints() { + InterceptorRegistry registry = mock(InterceptorRegistry.class); + InterceptorRegistration registration = mock(InterceptorRegistration.class); + when(registry.addInterceptor(any())).thenReturn(registration); + when(registration.addPathPatterns(any(String[].class))).thenReturn(registration); + + new WebConfig(mock(AuthInterceptor.class), mock(AdminInterceptor.class)).addInterceptors(registry); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String[].class); + verify(registration, atLeastOnce()).addPathPatterns(captor.capture()); + + List allPatterns = new ArrayList<>(); + captor.getAllValues().forEach(arr -> allPatterns.addAll(List.of(arr))); + + assertThat(allPatterns).contains( + "/api/auth/me", + "/api/auth/logout", + "/api/auth/password", + "/api/auth/verify-password", + "/api/auth/profile"); + } +}