From d4633eb2226b3cc6dee3c0b743e217bd42f068b1 Mon Sep 17 00:00:00 2001 From: choidongkuen Date: Mon, 12 Feb 2024 16:09:18 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=EC=9D=B8=EC=A6=9D=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#198)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JwtAuthenticationEntryPointTest.java | 67 +++++++++ .../security/JwtAuthenticationFilterTest.java | 142 ++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 src/test/java/net/teumteum/unit/core/security/JwtAuthenticationEntryPointTest.java create mode 100644 src/test/java/net/teumteum/unit/core/security/JwtAuthenticationFilterTest.java diff --git a/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationEntryPointTest.java b/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationEntryPointTest.java new file mode 100644 index 0000000..aa09f15 --- /dev/null +++ b/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationEntryPointTest.java @@ -0,0 +1,67 @@ +package net.teumteum.unit.core.security; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import net.teumteum.core.error.ErrorResponse; +import net.teumteum.core.security.filter.JwtAuthenticationEntryPoint; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.DelegatingServletOutputStream; +import org.springframework.security.core.AuthenticationException; + +@ExtendWith(MockitoExtension.class) +@DisplayName("JwtAuthenticationEntryPoint 단위 테스트의") +public class JwtAuthenticationEntryPointTest { + + @Mock + private ObjectMapper objectMapper; + + @Mock + private AuthenticationException authenticationException; + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @InjectMocks + private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + + @Nested + @DisplayName("JwtAuthenticationFilter 에서 인증 예외가 발생시") + class When_authentication_error_occurs_from_filter { + + @Test + @DisplayName("알맞은 예외 메시지와 관련 응답을 반환한다.") + void Return_error_response_with_message() throws IOException { + // given + var errorMessage = "Authentication Exception Occurred"; + var outputStream = new ByteArrayOutputStream(); + + given(request.getAttribute("exception")).willReturn(errorMessage); + given(response.getOutputStream()).willReturn(new DelegatingServletOutputStream(outputStream)); + + // when + jwtAuthenticationEntryPoint.commence(request, response, authenticationException); + + // then + verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); + verify(objectMapper, times(1)).writeValue(any(OutputStream.class), any(ErrorResponse.class)); + } + } +} diff --git a/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationFilterTest.java b/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationFilterTest.java new file mode 100644 index 0000000..9727bc4 --- /dev/null +++ b/src/test/java/net/teumteum/unit/core/security/JwtAuthenticationFilterTest.java @@ -0,0 +1,142 @@ +package net.teumteum.unit.core.security; + +import static net.teumteum.unit.common.SecurityValue.INVALID_ACCESS_TOKEN; +import static net.teumteum.unit.common.SecurityValue.VALID_ACCESS_TOKEN; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import java.io.IOException; +import net.teumteum.auth.service.AuthService; +import net.teumteum.core.property.JwtProperty; +import net.teumteum.core.security.UserAuthentication; +import net.teumteum.core.security.filter.JwtAuthenticationFilter; +import net.teumteum.core.security.service.JwtService; +import net.teumteum.user.domain.User; +import net.teumteum.user.domain.UserFixture; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +@ExtendWith(MockitoExtension.class) +@DisplayName("JwtAuthenticationFilter 단위 테스트의") +public class JwtAuthenticationFilterTest { + + @Mock + JwtService jwtService; + + @Mock + AuthService authService; + + @Mock + JwtProperty jwtProperty; + + @Mock + JwtProperty.Access access; + + @Mock + FilterChain filterChain; + + @InjectMocks + JwtAuthenticationFilter jwtAuthenticationFilter; + + @Nested + @DisplayName("API 요청시 JWT 파싱 및 회원 조회 로직은") + class Api_request_with_valid_jwt_unit { + + @BeforeEach + @AfterEach + void clearSecurityContextHolder() { + SecurityContextHolder.clearContext(); + } + + @Test + @DisplayName("유효한 JWT 인 경우, JWT 을 파싱하고 성공적으로 UserAuthentication 을 SecurityContext 에 저장한다.") + void Parsing_jwt_and_save_user_in_security_context() throws ServletException, IOException { + // given + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + given(jwtProperty.getAccess()).willReturn(access); + given(jwtProperty.getAccess().getHeader()).willReturn("Authorization"); + given(jwtProperty.getBearer()).willReturn("Bearer"); + + request.addHeader(jwtProperty.getAccess().getHeader(), + jwtProperty.getBearer() + " " + VALID_ACCESS_TOKEN); + + User user = UserFixture.getIdUser(); + + given(jwtService.validateToken(anyString())).willReturn(true); + given(authService.findUserByAccessToken(anyString())).willReturn(user); + + // when + jwtAuthenticationFilter.doFilterInternal(request, response, filterChain); + + // then + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + assertThat(authentication).isInstanceOf(UserAuthentication.class); + } + + @Test + @DisplayName("유효하지 않은 JWT 와 함께 요청이 들어오면, 요청 처리를 중단하고 에러 메세지를 반환한다.") + void Return_error_when_jwt_is_invalid() throws ServletException, IOException { + // given + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + given(jwtProperty.getAccess()).willReturn(access); + given(jwtProperty.getAccess().getHeader()).willReturn("Authorization"); + given(jwtProperty.getBearer()).willReturn("Bearer"); + + request.addHeader(jwtProperty.getAccess().getHeader(), + jwtProperty.getBearer() + " " + INVALID_ACCESS_TOKEN); + + given(jwtService.validateToken(anyString())).willReturn(false); + + // when + jwtAuthenticationFilter.doFilterInternal(request, response, filterChain); + + // then + assertThat(request.getAttribute("exception")).isEqualTo("요청에 대한 JWT 가 유효하지 않습니다."); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + assertThat(authentication).isNull(); + verify(filterChain, times(1)).doFilter(request, response); + } + + @Test + @DisplayName("JWT 가 존재하지 않는 경우, 요청 처리를 중단하고 에러 메세지를 반환한다.") + void Return_error_when_jwt_is_not_exist() throws ServletException, IOException { + // given + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + given(jwtProperty.getAccess()).willReturn(access); + given(jwtProperty.getAccess().getHeader()).willReturn("Authorization"); + given(jwtProperty.getBearer()).willReturn("Bearer"); + + request.addHeader(jwtProperty.getAccess().getHeader(), + jwtProperty.getBearer() + " "); + + // when + jwtAuthenticationFilter.doFilterInternal(request, response, filterChain); + + // then + assertThat(request.getAttribute("exception")).isEqualTo("요청에 대한 JWT 정보가 존재하지 않습니다."); + verify(jwtService, times(0)).validateToken(anyString()); + } + } +}