diff --git a/src/main/java/com/bit/lot/flower/auth/common/util/JsonBinderUtil.java b/src/main/java/com/bit/lot/flower/auth/common/util/JsonBinderUtil.java index 9d2fd094..02ec7b4e 100644 --- a/src/main/java/com/bit/lot/flower/auth/common/util/JsonBinderUtil.java +++ b/src/main/java/com/bit/lot/flower/auth/common/util/JsonBinderUtil.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import javax.servlet.http.HttpServletResponse; +import org.springframework.http.HttpStatus; public class JsonBinderUtil { @@ -17,6 +18,18 @@ public static HttpServletResponse setResponseWithJson(HttpServletResponse respon return response; } + + public static HttpServletResponse setRedirectURLWithPathVariableType(HttpServletResponse response, int status, + Object type) throws IOException { + response.setContentType("application/json"); + response.setStatus(HttpStatus.PERMANENT_REDIRECT.value()); + response.setCharacterEncoding("UTF-8"); + response.getWriter().write(getJsonFromType(type)); + response.sendRedirect(""); + return response; + } + + private static String getJsonFromType(Object type) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.writeValueAsString(type); diff --git a/src/main/java/com/bit/lot/flower/auth/oauth/OauthController.java b/src/main/java/com/bit/lot/flower/auth/oauth/OauthController.java deleted file mode 100644 index 2c283926..00000000 --- a/src/main/java/com/bit/lot/flower/auth/oauth/OauthController.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bit.lot.flower.auth.oauth; - -import com.bit.lot.flower.auth.oauth.facade.OauthLoginAccessTokenRequestFacade; -import com.bit.lot.flower.auth.oauth.facade.OauthUserMeInfoRequestFacade; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RestController; - - -@RequiredArgsConstructor -@RestController -public class OauthController { - - - private final OauthLoginAccessTokenRequestFacade oauthLoginRequestFacade; - private final OauthUserMeInfoRequestFacade userMeInfoRequestFacade; - -// @GetMapping("/login/oauth2/{provider}") -// public ResponseEntity requestSocialInfo(@RequestParam String code, @PathVariable -// AuthenticationProvider provider){ -// oauthLoginRequestFacade.request(provider,code); -// return null; -// } - -} diff --git a/src/main/java/com/bit/lot/flower/auth/oauth/facade/OauthLoginAccessTokenRequestFacade.java b/src/main/java/com/bit/lot/flower/auth/oauth/facade/OauthLoginAccessTokenRequestFacade.java deleted file mode 100644 index 3547f934..00000000 --- a/src/main/java/com/bit/lot/flower/auth/oauth/facade/OauthLoginAccessTokenRequestFacade.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.bit.lot.flower.auth.oauth.facade; - -import com.bit.lot.flower.auth.common.valueobject.AuthenticationProvider; -import com.bit.lot.flower.auth.oauth.util.access.GetKakaoAccessKeyHttpUtil; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -@RequiredArgsConstructor -@Component -public class OauthLoginAccessTokenRequestFacade { - private final GetKakaoAccessKeyHttpUtil getKakaoAccessKeyHttpUtil; - public String request(AuthenticationProvider provider, String code) { - if (provider.equals(AuthenticationProvider.kakao)) { - getKakaoAccessKeyHttpUtil.getAccessToken(code); - } - throw new IllegalArgumentException("존재 하지 않는 인증 제공자입니다."); - } - -} diff --git a/src/main/java/com/bit/lot/flower/auth/oauth/facade/OauthUserMeInfoRequestFacade.java b/src/main/java/com/bit/lot/flower/auth/oauth/facade/OauthUserMeInfoRequestFacade.java deleted file mode 100644 index 405672f7..00000000 --- a/src/main/java/com/bit/lot/flower/auth/oauth/facade/OauthUserMeInfoRequestFacade.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.bit.lot.flower.auth.oauth.facade; - -import org.springframework.stereotype.Component; - -@Component -public class OauthUserMeInfoRequestFacade { - - - -} diff --git a/src/main/java/com/bit/lot/flower/auth/oauth/http/util/RequestRestTemplateAccessTokenUtil.java b/src/main/java/com/bit/lot/flower/auth/oauth/http/util/RequestRestTemplateAccessTokenUtil.java deleted file mode 100644 index eb36a03d..00000000 --- a/src/main/java/com/bit/lot/flower/auth/oauth/http/util/RequestRestTemplateAccessTokenUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bit.lot.flower.auth.oauth.http.util; - -import com.bit.lot.flower.auth.oauth.dto.response.LoginResponseDto; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.stereotype.Component; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; - -@RequiredArgsConstructor -@Component -public class RequestRestTemplateAccessTokenUtil { - - private final RestTemplate restTemplate; - - public String request(String code, String clientId, String redirectURI, String requestURL) { - HttpHeaders headers = new HttpHeaders(); - headers.add("Content-type", "application/x-www-form-urlencoded; charset=utf-8"); - - MultiValueMap body = new LinkedMultiValueMap<>(); - - body.add("grant_type", "authorization_code"); - body.add("client_id", clientId); - body.add("redirect_uri", redirectURI); - body.add("code", code); - - LoginResponseDto loginResponseDto = restTemplate.postForObject( - requestURL, - new HttpEntity<>(body, headers), - LoginResponseDto.class); - - return loginResponseDto.getAccessToken(); - - } -} diff --git a/src/main/java/com/bit/lot/flower/auth/oauth/util/EncryptionUtil.java b/src/main/java/com/bit/lot/flower/auth/oauth/util/EncryptionUtil.java new file mode 100644 index 00000000..b50416cd --- /dev/null +++ b/src/main/java/com/bit/lot/flower/auth/oauth/util/EncryptionUtil.java @@ -0,0 +1,39 @@ +package com.bit.lot.flower.auth.oauth.util; + +import java.util.Base64; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class EncryptionUtil { + + @Value("${user.info.secret}") + private String SECRET_KEY; + + public String encrypt(String data) throws Exception { + Cipher cipher = getCipher(Cipher.ENCRYPT_MODE); + byte[] encryptedBytes = cipher.doFinal(data.getBytes()); + return Base64.getEncoder().encodeToString(encryptedBytes); + } + + public String decrypt(String encryptedData) throws Exception { + byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData); + Cipher cipher = getCipher(Cipher.DECRYPT_MODE); + byte[] decryptedBytes = cipher.doFinal(encryptedBytes); + return new String(decryptedBytes); + } + + private Cipher getCipher(int mode) throws Exception { + DESKeySpec desKeySpec = new DESKeySpec(SECRET_KEY.getBytes()); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey secretKey = keyFactory.generateSecret(desKeySpec); + + Cipher cipher = Cipher.getInstance("DES"); + cipher.init(mode, secretKey); + return cipher; + } +} diff --git a/src/main/java/com/bit/lot/flower/auth/oauth/util/UserInfoCipherHelper.java b/src/main/java/com/bit/lot/flower/auth/oauth/util/UserInfoCipherHelper.java new file mode 100644 index 00000000..2a2f8929 --- /dev/null +++ b/src/main/java/com/bit/lot/flower/auth/oauth/util/UserInfoCipherHelper.java @@ -0,0 +1,47 @@ +package com.bit.lot.flower.auth.oauth.util; + +import com.bit.lot.flower.auth.common.valueobject.AuthId; +import com.bit.lot.flower.auth.social.dto.command.SocialLoginRequestCommand; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@RequiredArgsConstructor +@Component +public class UserInfoCipherHelper { + + private final EncryptionUtil encryptionUtil; + + public String encrpyt(String oauthRedirectURL, + SocialLoginRequestCommand command) throws Exception { + + StringBuilder sb = new StringBuilder(); + sb.append(oauthRedirectURL) + .append("/") + .append(encryptionUtil.encrypt(command.getSocialId().toString())) + .append("/") + .append(encryptionUtil.encrypt(command.getNickname())) + .append("/") + .append(encryptionUtil.encrypt(command.getEmail())) + .append("/") + .append(command.getPhoneNumber()); + + return sb.toString(); + } + + + public SocialLoginRequestCommand decrypt(SocialLoginRequestCommand command) throws Exception { + String phoneNumber =encryptionUtil.decrypt(command.getPhoneNumber()); + String email = encryptionUtil.decrypt(command.getEmail()); + String socialId = encryptionUtil.decrypt(command.getSocialId().getValue().toString()); + String nickname = encryptionUtil.decrypt(command.getNickname()); + return createDecryptDto(phoneNumber, email, new AuthId(Long.valueOf(socialId)), nickname); + } + + + private SocialLoginRequestCommand createDecryptDto(String phoneNumber, String email, + AuthId socialId, String nickName) { + return SocialLoginRequestCommand.builder().phoneNumber(phoneNumber) + .socialId(socialId).nickname(nickName).email( + email).build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/bit/lot/flower/auth/oauth/util/access/GetKakaoAccessKeyHttpUtil.java b/src/main/java/com/bit/lot/flower/auth/oauth/util/access/GetKakaoAccessKeyHttpUtil.java deleted file mode 100644 index 02704d4f..00000000 --- a/src/main/java/com/bit/lot/flower/auth/oauth/util/access/GetKakaoAccessKeyHttpUtil.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bit.lot.flower.auth.oauth.util.access; - -import com.bit.lot.flower.auth.oauth.http.util.RequestRestTemplateAccessTokenUtil; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@RequiredArgsConstructor -@Component -public class GetKakaoAccessKeyHttpUtil { - - private final RequestRestTemplateAccessTokenUtil requestRestTemplateAccessTokenUtil; - - private final String requestURI = "https://kauth.kakao.com/oauth/token"; - @Value("${spring.security.oauth2.client.registration.kakao.client-id}") - private String clientId; - @Value("${spring.security.oauth2.client.registration.kakao.redirect-uri}") - private String redirectURI; - - public String getAccessToken(String code) { - return requestRestTemplateAccessTokenUtil.request(code, clientId, redirectURI, requestURI); - } - -} diff --git a/src/main/java/com/bit/lot/flower/auth/social/dto/command/SocialLoginRequestCommand.java b/src/main/java/com/bit/lot/flower/auth/social/dto/command/SocialLoginRequestCommand.java index 692fd892..2ac2186a 100644 --- a/src/main/java/com/bit/lot/flower/auth/social/dto/command/SocialLoginRequestCommand.java +++ b/src/main/java/com/bit/lot/flower/auth/social/dto/command/SocialLoginRequestCommand.java @@ -1,6 +1,7 @@ package com.bit.lot.flower.auth.social.dto.command; import com.bit.lot.flower.auth.common.valueobject.AuthId; +import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -11,8 +12,12 @@ @NoArgsConstructor @Getter public class SocialLoginRequestCommand { + @NotNull private AuthId socialId; + @NotNull private String email; private String phoneNumber; + @NotNull private String nickname; + } diff --git a/src/main/java/com/bit/lot/flower/auth/social/http/controller/SocialAuthRestController.java b/src/main/java/com/bit/lot/flower/auth/social/http/controller/SocialAuthRestController.java index c9ce3eaa..c318c280 100644 --- a/src/main/java/com/bit/lot/flower/auth/social/http/controller/SocialAuthRestController.java +++ b/src/main/java/com/bit/lot/flower/auth/social/http/controller/SocialAuthRestController.java @@ -1,6 +1,7 @@ package com.bit.lot.flower.auth.social.http.controller; import com.bit.lot.flower.auth.common.util.AuthIdCreator; +import com.bit.lot.flower.auth.oauth.util.UserInfoCipherHelper; import com.bit.lot.flower.auth.social.dto.command.SocialLoginRequestCommand; import com.bit.lot.flower.auth.social.dto.response.UserFeignLoginResponse; import com.bit.lot.flower.auth.social.http.helper.OauthLogoutFacadeHelper; @@ -11,6 +12,7 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -18,6 +20,7 @@ import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController @@ -28,14 +31,15 @@ public class SocialAuthRestController { private final OauthLogoutFacadeHelper oauthLogoutFacadeHelper; private final SocialAuthService socialAuthService; private final LoginSocialUserRequest userDataRequest; + private final UserInfoCipherHelper userInfoCipherHelper; @ApiOperation(value = "유저 로그인", notes = "Authroization: Bearer 토큰 생성, Refresh토큰" + "Redis에 생성, HttpOnlyCookie에 생성") @PostMapping("/social/login") public ResponseEntity loginWithUserServiceResponse( - HttpServletRequest request) { - SocialLoginRequestCommand dto = (SocialLoginRequestCommand) request.getAttribute("command"); - UserFeignLoginResponse userFeignLoginResponse = userDataRequest.request(dto); + @Valid @RequestBody SocialLoginRequestCommand command) throws Exception { + SocialLoginRequestCommand decryptCommand = userInfoCipherHelper.decrypt(command); + UserFeignLoginResponse userFeignLoginResponse = userDataRequest.request(decryptCommand); return ResponseEntity.ok(userFeignLoginResponse); } diff --git a/src/main/java/com/bit/lot/flower/auth/social/security/OauthAuthenticationSuccessHandler.java b/src/main/java/com/bit/lot/flower/auth/social/security/OauthAuthenticationSuccessHandler.java index 9f5efbaf..dc435a2e 100644 --- a/src/main/java/com/bit/lot/flower/auth/social/security/OauthAuthenticationSuccessHandler.java +++ b/src/main/java/com/bit/lot/flower/auth/social/security/OauthAuthenticationSuccessHandler.java @@ -1,14 +1,17 @@ package com.bit.lot.flower.auth.social.security; -import com.bit.lot.flower.auth.common.util.JsonBinderUtil; +import com.bit.lot.flower.auth.oauth.util.EncryptionUtil; +import com.bit.lot.flower.auth.oauth.util.UserInfoCipherHelper; import com.bit.lot.flower.auth.social.dto.command.SocialLoginRequestCommand; +import com.bit.lot.flower.auth.social.exception.SocialAuthException; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.core.user.DefaultOAuth2User; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; @@ -18,6 +21,9 @@ @RequiredArgsConstructor public class OauthAuthenticationSuccessHandler implements AuthenticationSuccessHandler { + private final UserInfoCipherHelper userInfoCipherHelper; + @Value("${client.redirect.domain}") + private String oauthRedirectURL; private final OauthUserInfoFacade oauthUserInfoFacade; @Override @@ -30,12 +36,20 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, - Authentication authentication) throws IOException { + Authentication authentication) { DefaultOAuth2User defaultOAuth2User = (DefaultOAuth2User) authentication.getPrincipal(); SocialLoginRequestCommand command = oauthUserInfoFacade.getCommand(defaultOAuth2User); - JsonBinderUtil.setResponseWithJson(response, 200, command); + try { + response.sendRedirect(responseWithEncodedURL(oauthRedirectURL, command)); + } catch (Exception e) { + throw new SocialAuthException("암호화를 진행할 수 없습니다."); + } } + private String responseWithEncodedURL(String oauthRedirectURL, SocialLoginRequestCommand command) + throws Exception { + return userInfoCipherHelper.encrpyt(oauthRedirectURL, command); + } } diff --git a/src/main/java/com/bit/lot/flower/auth/social/security/OauthUserInfoFacade.java b/src/main/java/com/bit/lot/flower/auth/social/security/OauthUserInfoFacade.java index 1b4efcc9..727b2822 100644 --- a/src/main/java/com/bit/lot/flower/auth/social/security/OauthUserInfoFacade.java +++ b/src/main/java/com/bit/lot/flower/auth/social/security/OauthUserInfoFacade.java @@ -40,11 +40,16 @@ private SocialLoginRequestCommand getKakaoDto(DefaultOAuth2User oAuth2User) { String email = kakaoAccount.get("email"); String phoneNumber = kakaoAccount.get("phone_number"); String nickname = properties.get("nickname"); + return create(id, email, phoneNumber, nickname); + + } + + private SocialLoginRequestCommand create(String id, String email, String phoneNumber, + String nickname) { return SocialLoginRequestCommand.builder().email(email).nickname(nickname) .phoneNumber(OauthInfoConvertor.convertInternationalPhoneNumberToDomestic(phoneNumber)) .socialId(AuthId.builder().value(Long.valueOf(id)).build()).build(); } - } \ No newline at end of file diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index aa6bd83c..f54aa17e 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -28,7 +28,7 @@ spring: client-id: 7f313aaa30b302cd7ae2b48cf2d2b7cd client-secret: Wl5VDUbX9KsRymQW2S4MhoPvAPqdD7kC client-authentication-method: client_secret_post - redirect-uri: http://localhost:9000/oauth/authorize + redirect-uri: http://localhost:8000/api/auth/oauth2/authorization/kakao authorization-grant-type: authorization_code admin-key: ffc238f9c4e55c2fa85f551f882eda68 client-name: kakao @@ -86,4 +86,14 @@ management: exposure: include: - "refresh" - - "bus-refresh" \ No newline at end of file + - "bus-refresh" + +client: + redirect: + domain: http://localhost:3000/login/oauth + +user: + info: + secret: user-secret-user-secret-user-secret-user-secret-user-secret + + diff --git a/src/test/java/com/bit/lot/flower/auth/social/filter/SocialAuthorizationFilterTest.java b/src/test/java/com/bit/lot/flower/auth/social/filter/SocialAuthorizationFilterTest.java deleted file mode 100644 index fb19fd05..00000000 --- a/src/test/java/com/bit/lot/flower/auth/social/filter/SocialAuthorizationFilterTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.bit.lot.flower.auth.social.filter; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; - -import com.bit.lot.flower.auth.common.util.JwtUtil; -import com.bit.lot.flower.auth.common.valueobject.Role; -import com.bit.lot.flower.auth.common.valueobject.SecurityPolicyStaticValue; -import com.bit.lot.flower.auth.social.http.filter.SocialAuthorizationFilter; -import io.jsonwebtoken.MalformedJwtException; -import java.util.Map; -import javax.transaction.Transactional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; -@TestPropertySource(locations="classpath:application-test.yml") -@ActiveProfiles("test") -@Transactional -@ExtendWith(SpringExtension.class) -@SpringBootTest - class SocialAuthorizationFilterTest { - - @Autowired - SocialAuthorizationFilter authorizationFilter; - @Autowired - WebApplicationContext webApplicationContext; - MockMvc mvc; - - Long testUserId = 1L; - - @BeforeEach - void setUp() { - mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilter(authorizationFilter) - .build(); - } - - - private String createUnValidToken() { - return "unValidRandomToken"; - } - - - private MvcResult requestWithUnValidToken() - throws Exception { - return mvc.perform(MockMvcRequestBuilders.post("/social/{provider}/logout", "kakao") - .header("Authorization", "Bearer " + anyString())) - .andExpect(MockMvcResultMatchers.status().isOk()).andReturn(); - } - - private MvcResult requestWithoutTokenAtHeader() - throws Exception { - return mvc.perform(MockMvcRequestBuilders.post("/social/{provider}/logout", "kakao")) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) - .andReturn(); - } - - - @DisplayName("헤더에 토큰이 없을 때 Throw IllegalArgumentException 테스트") - @Test - void SocialAuthorizationFilterTest_WhenThereIsNotTokenAtHeader_ThrowIllegalArgumentException() { - JwtUtil.generateAccessToken(anyString()); - assertThrows(IllegalArgumentException.class, () -> { - requestWithoutTokenAtHeader(); - }); - } - - @DisplayName("헤더에 토큰이 있지만 ROLE_SOCIAL_USER의 claim을 가지고 있지 않을 때 Throw NullPointExcpetion 테스트") - @Test - void SocialAuthorizationFilterTest_WhenThereIsTokenAtHeaderButNoRole_ThrowNullPointException() { - JwtUtil.generateAccessToken(anyString()); - assertThrows(NullPointerException.class, () -> { - requestWithUnValidToken(); - }); - } - - - -} diff --git a/src/test/java/com/bit/lot/flower/auth/social/filter/SocialLoginMvcTest.java b/src/test/java/com/bit/lot/flower/auth/social/filter/SocialLoginMvcTest.java deleted file mode 100644 index 9b3118ce..00000000 --- a/src/test/java/com/bit/lot/flower/auth/social/filter/SocialLoginMvcTest.java +++ /dev/null @@ -1,251 +0,0 @@ -package com.bit.lot.flower.auth.social.filter; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import com.bit.lot.flower.auth.common.util.RedisRefreshTokenUtil; -import com.bit.lot.flower.auth.social.dto.command.SocialLoginRequestCommand; -import com.bit.lot.flower.auth.social.dto.response.UserFeignLoginResponse; -import com.bit.lot.flower.auth.social.entity.SocialAuth; -import com.bit.lot.flower.auth.social.exception.SocialAuthException; -import com.bit.lot.flower.auth.social.message.LoginSocialUserRequest; -import com.bit.lot.flower.auth.social.repository.SocialAuthJpaRepository; -import com.bit.lot.flower.auth.common.valueobject.AuthId; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.time.ZonedDateTime; -import javax.transaction.Transactional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.data.redis.core.RedisKeyValueAdapter; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.http.MediaType; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@TestPropertySource(locations = "classpath:application-test.yml") -@ActiveProfiles("test") -@Transactional -@ExtendWith(SpringExtension.class) -@SpringBootTest -class SocialLoginMvcTest { - - Long testId = 1L; - @Value("${cookie.refresh.token.name}") - String refreshTokenName; - @Value("${security.authorization.header.name}") - String authorizationHeaderName; - @MockBean - LoginSocialUserRequest loginSocialUserRequest; - @Autowired - SocialAuthJpaRepository socialAuthJpaRepository; - @Qualifier("socialAuthenticationFilter") - @Autowired - UsernamePasswordAuthenticationFilter socialAuthenticationFilter; - @Autowired - SocialAuthJpaRepository repository; - @Autowired - WebApplicationContext webApplicationContext; - @MockBean - RedisTemplate redisTemplate; - @MockBean - RedisRefreshTokenUtil redisRefreshTokenUtil; - @MockBean - RedisKeyValueAdapter keyValueAdapter; - - MockMvc mvc; - - - @BeforeEach - public void setUp() { - mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) - .addFilter(socialAuthenticationFilter) - .build(); - } - - private AuthId getAuthIdFromValue(Long value) { - return AuthId.builder().value(value).build(); - } - - private SocialLoginRequestCommand getSocialLoginRequestCommand(Long value) { - return SocialLoginRequestCommand.builder().socialId(getAuthIdFromValue(value)) - .email("test@gmail.com").nickname("testNickName").build(); - } - - private void saveStatusNotRecentlyOut(SocialLoginRequestCommand command) { - repository.save(new SocialAuth(command.getSocialId().getValue(), false, null)); - } - - - private void saveStatusRecentlyOutNotPassedOneDay(SocialLoginRequestCommand command) { - repository.save(new SocialAuth(command.getSocialId().getValue(), true, - ZonedDateTime.now().minusHours(23L))); - } - - private void saveStatusRecentlyOutPassedOneDay(SocialLoginRequestCommand command) { - repository.save(new SocialAuth(command.getSocialId().getValue(), true, - ZonedDateTime.now().minusHours(25L))); - } - - private String asJsonString(Object obj) throws JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.writeValueAsString(obj); - } - - - private MvcResult socialUserLoginRequest(SocialLoginRequestCommand command) - throws Exception { - return mvc.perform(MockMvcRequestBuilders - .post("/social/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(command))) - .andExpect(status().is2xxSuccessful()) - .andReturn(); - } - - @DisplayName("유저가 존재하지 않을 때 소셜 자동 회원가입 확인") - @Test - void socialUserLoginTest_WhenUserIsNotExist_UserIsCreated() throws Exception { - - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - - socialUserLoginRequest(command); - assertTrue(repository.findById(command.getSocialId().getValue()).isPresent()); - - } - - @DisplayName("유저가 존재하지 않을 때 소셜 자동 회원가입 후 JWT토큰 확인") - @Test - void socialUserLoginTest_WhenUserIsNotExist_JWTTokenInResponse() throws Exception { - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - MvcResult resultWithJwtToken = socialUserLoginRequest(command); - assertNotNull( - resultWithJwtToken.getResponse().getHeader(authorizationHeaderName)); - } - - - @DisplayName("유저가 존재하지 않을 때 소셜 자동 회원가입 후 Refresh토큰 Cookie에 담겨있는지 확인") - @Test - void socialUserLoginTest_WhenUserIsNotExist_RefreshTokenInCookie() throws Exception { - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - MvcResult refreshTokenAtCookieResponse = socialUserLoginRequest(command); - assertNotNull(refreshTokenAtCookieResponse.getResponse().getCookie(refreshTokenName)); - - } - - @DisplayName("유저가 존재하지 않을 때 소셜 자동 회원가입 후 Refresh토큰 Redis에 담겨있는지 확인") - @Test - void socialUserLoginTest_WhenUserIsNotExist_RefreshInRedis() throws Exception { - - Mockito.doNothing().when(redisRefreshTokenUtil) - .saveRefreshToken("1", null,3660L); - - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - - socialUserLoginRequest(command); - - } - - @DisplayName("유저가 존재하고 최근 회원탈퇴를 하지 않은 유저 로그인 성공 테스트") - @Test - void socialUserLoginTest_WhenUserIsExistWithNotOutRecentlyStatus_Status200() throws Exception { - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - saveStatusNotRecentlyOut(command); - MvcResult status200Result = socialUserLoginRequest(command); - assertEquals(200, status200Result.getResponse().getStatus()); - } - - @DisplayName("유저가 존재하고 최근 회원탈퇴를 한 후 24시간이 지나지 않은 회원 에러 확인 테스트") - @Test - void socialUserLoginTest_WhenUserIsExistWithOutRecentlyStatusAndTheTimeIsNotPassed24H_ThrowSocialAuthException() { - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - saveStatusRecentlyOutNotPassedOneDay(command); - assertThrowsExactly(SocialAuthException.class, () -> { - socialUserLoginRequest(command); - }); - - } - - @DisplayName("유저가 존재하고 최근 회원탈퇴를 한 후 24시간이 지난 회원 isRecentlyOut 상태 false 변경") - @Test - void socialUserLoginTest_WhenUserIsExistWithOutRecentlyStatusAndTheTimeIsPassed24H_UserRecentlyStatusToFalse() - throws Exception { - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - saveStatusRecentlyOutPassedOneDay(command); - socialUserLoginRequest(command); - assertTrue(repository.findById(command.getSocialId().getValue()).get().isRecentlyOut()); - - } - - - @DisplayName("유저가 존재하고 최근 회원탈퇴를 한 후 24시간이 지난 회원 로그인 성공 status 200") - @Test - void socialUserLoginTest_WhenUserIsExistWithOutRecentlyStatusAndTheTimeIsPassed24H_Status() - throws Exception { - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - saveStatusRecentlyOutPassedOneDay(command); - socialUserLoginRequest(command); - } - - - /** - * - * 이후 JWT토큰과 Redis, Coookie는 모든 같은 클래스 메소드 내에서 실행되는 로직이라 - * 위의 테스트 코드와 같다. - */ - @DisplayName("유저가 존재하고 최근 회원탈퇴를 한 후 24시간이 지난 회원 로그인 성공후 header에 JWT토큰 존재") - @Test - void socialUserLoginTest_WhenUserIsExistWithOutRecentlyStatusAndTheTimeIsPassed24H_JwtTokenIsExistedInHeader() - throws Exception { - SocialLoginRequestCommand command = getSocialLoginRequestCommand(testId); - when(loginSocialUserRequest.request(command)).thenReturn( - mock(UserFeignLoginResponse.class)); - saveStatusRecentlyOutPassedOneDay(command); - MvcResult resultWithJwtToken = socialUserLoginRequest(command); - assertNotNull( - resultWithJwtToken.getResponse().getHeader(authorizationHeaderName)); - } - -} diff --git a/src/test/java/com/bit/lot/flower/auth/store/filter/StoreManagerAuthorizationFilterTest.java b/src/test/java/com/bit/lot/flower/auth/store/filter/StoreManagerAuthorizationFilterTest.java deleted file mode 100644 index 914bc21e..00000000 --- a/src/test/java/com/bit/lot/flower/auth/store/filter/StoreManagerAuthorizationFilterTest.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.bit.lot.flower.auth.store.filter; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.bit.lot.flower.auth.common.util.JwtUtil; -import com.bit.lot.flower.auth.common.util.RedisBlackListTokenUtil; -import com.bit.lot.flower.auth.common.util.RedisRefreshTokenUtil; -import com.bit.lot.flower.auth.store.entity.StoreManagerAuth; -import com.bit.lot.flower.auth.store.exception.StoreManagerAuthException; -import com.bit.lot.flower.auth.store.http.filter.StoreMangerAuthorizationFilter; -import com.bit.lot.flower.auth.store.repository.StoreManagerAuthRepository; -import com.bit.lot.flower.auth.store.valueobject.StoreManagerStatus; -import io.jsonwebtoken.MalformedJwtException; -import java.util.Map; -import javax.transaction.Transactional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.data.redis.core.RedisKeyValueAdapter; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.util.NestedServletException; - -@TestPropertySource(locations="classpath:application-test.yml") -@ActiveProfiles("test") -@Transactional -@ExtendWith(SpringExtension.class) -@SpringBootTest -public class StoreManagerAuthorizationFilterTest { - - Long storeManagerPk = 1L; - @Value("${store.manager.id}") - String email = "id"; - @Value("${store.manager.password}") - String password; - @Autowired - StoreManagerAuthRepository repository; - @Autowired - StoreMangerAuthorizationFilter authorizationFilter; - @Autowired - WebApplicationContext webApplicationContext; - @MockBean - RedisTemplate redisTemplate; - @MockBean - RedisBlackListTokenUtil redisBlackListTokenUtil; - @MockBean - RedisKeyValueAdapter keyValueAdapter; - - MockMvc mvc; - final String claimRoleName = "ROLE"; - - - @BeforeEach - void setUp() { - mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilter(authorizationFilter) - .build(); - } - - private void saveValidStoreManagerUser() { - repository.save(StoreManagerAuth.builder().email(email).password(password).id(storeManagerPk) - .status(StoreManagerStatus.ROLE_STORE_MANAGER_PERMITTED).lastLogoutTime(null).build()); - } - - private String createUnValidToken() { - return "unValidRandomToken"; - } - - private String createValidToken(StoreManagerStatus storeManagerStatus) { - Map claimMap = JwtUtil.addClaims(claimRoleName, - storeManagerStatus); - return JwtUtil.generateAccessTokenWithClaims(String.valueOf(storeManagerPk), claimMap); - } - - private MvcResult requestWithStatusToken(StoreManagerStatus storeManagerStatus) - throws Exception { - return mvc.perform(MockMvcRequestBuilders.post("/stores/logout") - .header("Authorization", "Bearer " + createValidToken(storeManagerStatus))).andReturn(); - } - - private MvcResult requestWithoutStatusToken() - throws Exception { - return mvc.perform(MockMvcRequestBuilders.post("/stores/logout") - .header("Authorization", "Bearer " + createUnValidToken())) - .andExpect(MockMvcResultMatchers.status().isOk()).andReturn(); - } - - private MvcResult requestWithNoTokenAtHeader() - throws Exception { - return mvc.perform(MockMvcRequestBuilders.post("/stores/logout")) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) - .andReturn(); - } - - - /** - * @throws IllegalArgumentException 해당 error를 해당 Filter에서 try catch하지 않는 이유는 해당 error를 - * JwtAuthetnicationFitler에서 잡아주기 때문이다. JwtAuthenticationFilter를 - * 거치지 않고 해당 Filter를 거치지 않는 경우는 없다. - */ - - @DisplayName("스토어 매니저 JWT토큰이 존재하지 않을 때 IllegalArgumentException catch") - @Test - void StoreManagerTokenAuthorizationTest_WhenTokenIsNotExist_CatchIllegalArgumentException() { - assertThrows(IllegalArgumentException.class, () -> { - requestWithNoTokenAtHeader(); - }); - } - - /** - * JwtUtil.generateAccessToken(testUserId) 해당 코드를 작성하는 이유는 accesskey를 등록하기 위해서이다. accesskey를 등록하지 - * 않으면 무조건 IllegalArgumentException이 전파된다. - */ - - @DisplayName("토큰이 발급된 이후 JWT토큰이 존재하지 않을 때 MalformedJwtException catch") - @Test - void StoreManagerTokenAuthorizationTest_WhenTokenIsExistAfterLoginAndAccessKeyExist_ThrowMalformedJwtException() { - JwtUtil.generateAccessToken(email); - assertThrows(NullPointerException.class, () -> { - requestWithoutStatusToken(); - }); - } - - @DisplayName("스토어매니저 상태 Pending일 경우 Throw StoreManagerAuthException") - @Test - void StoreManagerTokenAuthorizationTest_WhenStoreManagerUserIsPending_ThrowStoreManagerAuthException() - throws Exception { - assertThrowsExactly(NullPointerException.class, - () -> { - requestWithStatusToken(StoreManagerStatus.ROLE_STORE_MANAGER_PENDING); - }); - } - - @DisplayName("스토어매니저 상태 Denined일 경우 Throw StoreManagerAuthException") - @Test - void StoreManagerTokenAuthorizationTest_WhenStoreManagerUserIsDenied_ThrowStoreManagerAuthException() - throws Exception { - assertThrowsExactly(NullPointerException.class, - () -> { - requestWithStatusToken(StoreManagerStatus.ROLE_STORE_MANAGER_DENIED); - }); - } - - @DisplayName("스토어매니저 상태 Permitted일 경우 status 200") - @Test - void StoreManagerTokenAuthorizationTest_WhenStoreManagerUserIsPermitted_Status200() - throws Exception { - saveValidStoreManagerUser(); - assertThrows(NullPointerException.class, () -> { - requestWithStatusToken(StoreManagerStatus.ROLE_STORE_MANAGER_PERMITTED).getResponse(); - }); - - } - - -} diff --git a/src/test/java/com/bit/lot/flower/auth/store/filter/StoreManagerLoginMvcTest.java b/src/test/java/com/bit/lot/flower/auth/store/filter/StoreManagerLoginMvcTest.java deleted file mode 100644 index d5c82700..00000000 --- a/src/test/java/com/bit/lot/flower/auth/store/filter/StoreManagerLoginMvcTest.java +++ /dev/null @@ -1,240 +0,0 @@ -package com.bit.lot.flower.auth.store.filter; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import com.bit.lot.flower.auth.common.valueobject.AuthId; -import com.bit.lot.flower.auth.store.exception.StoreManagerAuthException; -import com.bit.lot.flower.auth.common.util.RedisRefreshTokenUtil; -import com.bit.lot.flower.auth.store.dto.StoreManagerLoginDto; -import com.bit.lot.flower.auth.store.entity.StoreManagerAuth; -import com.bit.lot.flower.auth.store.http.StoreManagerNameRequest; -import com.bit.lot.flower.auth.store.http.feign.dto.StoreManagerNameDto; - -import com.bit.lot.flower.auth.store.repository.StoreManagerAuthRepository; -import com.bit.lot.flower.auth.store.valueobject.StoreManagerStatus; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.Random; -import javax.transaction.Transactional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.data.redis.core.RedisKeyValueAdapter; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.http.MediaType; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@TestPropertySource(locations = "classpath:application-test.yml") -@ActiveProfiles("test") -@Transactional -@ExtendWith(SpringExtension.class) -@SpringBootTest -class StoreManagerLoginMvcTest { - - final Long testId = 1L; - final String unValidStoreManagerId = "unValidStoreManagerId"; - final String unValidStoreManagerPassword = "unValidStoreManagerPassword"; - @Value("${store.manager.id}") - String email; - @Value("${store.manager.password}") - String password; - @Value("${cookie.refresh.token.name}") - String refreshTokenName; - @Value("${security.authorization.header.name}") - String authorizationHeaderName; - - @Autowired - StoreManagerAuthRepository repository; - @Qualifier("storeManagerAuthenticationFilter") - @Autowired - UsernamePasswordAuthenticationFilter authenticationFilter; - @Autowired - BCryptPasswordEncoder encoder; - @Autowired - WebApplicationContext webApplicationContext; - @MockBean - StoreManagerNameRequest storeManagerNameRequest; - @MockBean - RedisTemplate redisTemplate; - @MockBean - RedisRefreshTokenUtil redisRefreshTokenUtil; - @MockBean - RedisKeyValueAdapter keyValueAdapter; - - Random randomCreator; - - MockMvc mvc; - - - @BeforeEach - public void setUp() { - mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilter(authenticationFilter) - .build(); - randomCreator = new Random(); - } - - private void saveEncodedPasswordPermittedStoreManager() { - repository.save( - StoreManagerAuth.builder().lastLogoutTime(null).password(encoder.encode(password)).email( - email) - .status( - StoreManagerStatus.ROLE_STORE_MANAGER_PERMITTED).build()); - } - - - private void saveEncodedPasswordPendingStoreManager() { - repository.save( - StoreManagerAuth. - builder(). - lastLogoutTime(null). - password(encoder.encode(password)). - email(email). - id(testId). - status(StoreManagerStatus.ROLE_STORE_MANAGER_PENDING). - build()); - } - - private String asJsonString(Object obj) throws JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.writeValueAsString(obj); - } - - - private StoreManagerLoginDto LoginValidStoreManagerAccount() { - return StoreManagerLoginDto.builder().email(email).password(password).build(); - } - - - private StoreManagerLoginDto createIdAndPasswordMistMatchedStoreManagerAccount() { - return StoreManagerLoginDto.builder().email(unValidStoreManagerId) - .password(unValidStoreManagerPassword).build(); - } - - - private MvcResult getValidStoreManagerResponse(StoreManagerLoginDto validUserDto) - throws Exception { - return mvc.perform(MockMvcRequestBuilders - .post("/stores/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(validUserDto))) - .andExpect(status().is2xxSuccessful()) - .andReturn(); - } - - private MvcResult getUnValidStoreManagerResponse(StoreManagerLoginDto unValidUserDto) - throws Exception { - return mvc.perform(MockMvcRequestBuilders - .post("/stores/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(unValidUserDto))) - .andExpect(status().is4xxClientError()) - .andReturn(); - } - - - @DisplayName("스토어매니저 로그인시 JWT토큰 response에 존재 여부 체크 테스트") - @Test - void storeManagerLogin_WhenStoreManagerISExist_JWTTokenInResponse() throws Exception { - when(storeManagerNameRequest.getName(any(AuthId.class))).thenReturn(mock( - StoreManagerNameDto.class)); - - saveEncodedPasswordPermittedStoreManager(); - - MvcResult validStoreManger = getValidStoreManagerResponse( - LoginValidStoreManagerAccount()); - assertNotNull( - validStoreManger.getResponse().getHeader(authorizationHeaderName)); - } - - - @DisplayName("스토어매니저 로그인시 refresh토큰 HttpOnly쿠키에 존재 여부 체크 테스트") - @Test - void storeManagerLogin_WhenStoreManagerIsExist_RefreshTokenInHttpOnlyCookie() throws Exception { - when(storeManagerNameRequest.getName(any(AuthId.class))).thenReturn(mock( - StoreManagerNameDto.class)); - - saveEncodedPasswordPermittedStoreManager(); - - MvcResult validStoreManager = getValidStoreManagerResponse( - LoginValidStoreManagerAccount()); - assertNotNull(validStoreManager.getResponse().getCookie(refreshTokenName)); - - - } - - @DisplayName("스토어매니저 로그인시 refresh토큰 Redis에 존재 여부 체크 테스트") - @Test - void storeManagerLogin_WhenStoreManagerIsExist_RefreshTokenInRedis() throws Exception { - when(storeManagerNameRequest.getName(any(AuthId.class))).thenReturn(mock( - StoreManagerNameDto.class)); - - Mockito.doNothing().when(redisRefreshTokenUtil) - .saveRefreshToken("2", null, - 3660L); - - saveEncodedPasswordPermittedStoreManager(); - - getValidStoreManagerResponse( - LoginValidStoreManagerAccount()); - - - } - - @DisplayName("스토어매니저 상태 Pending일 경우 ThrowStoreMangerAuthException") - @Test - void storeManagerLogin_WhenStoreManagerIsExistButStatusIsPending_ThrowStoreMangerAuthException() { - when(storeManagerNameRequest.getName(any(AuthId.class))).thenReturn(mock( - StoreManagerNameDto.class)); - - saveEncodedPasswordPendingStoreManager(); - - assertThrowsExactly(StoreManagerAuthException.class, () -> { - getUnValidStoreManagerResponse(LoginValidStoreManagerAccount()); - }); - - - } - - /* - 틀린 계정으로 로그인을 시도하기에 어떤 entity를 저장해도 상관없다. - */ - @DisplayName("스토어매니저 올바르지 않은 계정으로 로그인시 BadCredentialExceptionThrow 테스트 ") - @Test - void storeManagerLogin_WhenStoreManagerIsNotExist_ThrowBadCredentialException() throws Exception { - when(storeManagerNameRequest.getName(any(AuthId.class))).thenReturn(mock( - StoreManagerNameDto.class)); - - saveEncodedPasswordPendingStoreManager(); - - assertEquals(401, getUnValidStoreManagerResponse( - createIdAndPasswordMistMatchedStoreManagerAccount()).getResponse().getStatus()); - } - - -} diff --git a/src/test/java/com/bit/lot/flower/auth/system/filter/SystemAdminAuthorizationFilterTest.java b/src/test/java/com/bit/lot/flower/auth/system/filter/SystemAdminAuthorizationFilterTest.java deleted file mode 100644 index af1ab0c8..00000000 --- a/src/test/java/com/bit/lot/flower/auth/system/filter/SystemAdminAuthorizationFilterTest.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.bit.lot.flower.auth.system.filter; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; - -import com.bit.lot.flower.auth.common.util.JwtUtil; -import com.bit.lot.flower.auth.common.util.RedisBlackListTokenUtil; -import com.bit.lot.flower.auth.common.util.RedisRefreshTokenUtil; -import com.bit.lot.flower.auth.common.valueobject.Role; -import com.bit.lot.flower.auth.common.valueobject.SecurityPolicyStaticValue; -import com.bit.lot.flower.auth.system.admin.http.filter.SystemAdminAuthorizationFilter; -import io.jsonwebtoken.MalformedJwtException; -import java.util.Map; -import javax.transaction.Transactional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.data.redis.core.RedisKeyValueAdapter; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@TestPropertySource(locations="classpath:application-test.yml") -@ActiveProfiles("test") -@Transactional -@ExtendWith(SpringExtension.class) -@SpringBootTest -class SystemAdminAuthorizationFilterTest { - - @Autowired - private SystemAdminAuthorizationFilter authorizationFilter; - @Autowired - private WebApplicationContext webApplicationContext; - @MockBean - RedisTemplate redisTemplate; - @MockBean - RedisBlackListTokenUtil redisBlackListTokenUtil; - @MockBean - RedisRefreshTokenUtil redisRefreshTokenUtil; - @MockBean - RedisKeyValueAdapter keyValueAdapter; - private MockMvc mvc; - - - String testUserId = "id"; - - private String unValidToken() { - return "unValidRandomToken"; - } - - private String validToken() { - Map claimMap = JwtUtil.addClaims(SecurityPolicyStaticValue.CLAIMS_ROLE_KEY_NAME, - Role.ROLE_SYSTEM_ADMIN.name()); - return JwtUtil.generateAccessTokenWithClaims(testUserId, claimMap); - } - - - private MvcResult requestWithValidToken() - throws Exception { - return mvc.perform(MockMvcRequestBuilders.post("/admin/logout") - .header("Authorization", "Bearer " + validToken())) - .andExpect(MockMvcResultMatchers.status().isOk()).andReturn(); - } - - private MvcResult requestWithUnValidToken() - throws Exception { - return mvc.perform(MockMvcRequestBuilders.post("/admin/logout") - .header("Authorization", "Bearer " + unValidToken())) - .andExpect(MockMvcResultMatchers.status().isOk()).andReturn(); - } - - private MvcResult requestWithNoTokenAtHeader() - throws Exception { - return mvc.perform(MockMvcRequestBuilders.post("/admin/logout")) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) - .andReturn(); - } - - @BeforeEach - void setUp() { - mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilter(authorizationFilter) - .build(); - } - - - /** - * @throws IllegalArgumentException 해당 error를 해당 Filter에서 try catch하지 않는 이유는 해당 error를 - * JwtAuthetnicationFitler에서 잡아주기 때문이다. JwtAuthenticationFilter를 - * 거치지 않고 해당 Filter를 거치지 않는 경우는 없다. - */ - - @DisplayName("JWT토큰이 존재하지 않을 때 IllegalArgumentException catch") - @Test - void systemAdminTokenAuthorizationTest_WhenTokenIsNotExist_CatchJwtException() - throws IllegalArgumentException { - assertThrows(IllegalArgumentException.class, () -> { - requestWithNoTokenAtHeader(); - }); - } - - /** - * JwtUtil.generateAccessToken(testUserId) 해당 코드를 작성하는 이유는 accesskey를 등록하기 위해서이다. accesskey를 등록하지 - * 않으면 무조건 IllegalArgumentException이 전파된다. - */ - - @DisplayName("토큰이 발급된 이후 JWT토큰이 존재하지 않을 때 MalformedJwtException catch") - @Test - void systemAdminTokenAuthorizationTest_WhenTokenIsExistAfterLoginAndAccessKeyExist_ThrowMalformedJwtException() { - JwtUtil.generateAccessToken(testUserId); - assertThrows(NullPointerException.class, () -> { - requestWithUnValidToken(); - }); - } - - - @DisplayName("JWT토큰이 valid할 때,Role이 정상적으로 담겨있을 때 status code 200") - @Test - void systemAdminTokenAuthorizationTest_WhenTokenIsExistAfterLoginAndGeneratedAccessToken_status200() - throws Exception { - assertThrows(NullPointerException.class, () -> { - requestWithValidToken(); - }); - } - -} diff --git a/src/test/java/com/bit/lot/flower/auth/system/filter/SystemAdminLoginMvcTest.java b/src/test/java/com/bit/lot/flower/auth/system/filter/SystemAdminLoginMvcTest.java deleted file mode 100644 index 25666f3f..00000000 --- a/src/test/java/com/bit/lot/flower/auth/system/filter/SystemAdminLoginMvcTest.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.bit.lot.flower.auth.system.filter; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.verify; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - - -import com.bit.lot.flower.auth.common.util.RedisRefreshTokenUtil; -import com.bit.lot.flower.auth.system.admin.dto.SystemAdminLoginDto; -import com.bit.lot.flower.auth.system.admin.exception.SystemAdminAuthException; -import com.bit.lot.flower.auth.system.admin.http.filter.SystemAdminAuthenticationFilter; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import javax.transaction.Transactional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.data.redis.core.RedisKeyValueAdapter; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.http.MediaType; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -@TestPropertySource(locations="classpath:application-test.yml") -@ActiveProfiles("test") -@Transactional -@ExtendWith(SpringExtension.class) -@SpringBootTest -class SystemAdminLoginMvcTest { - - @Value("${system.admin.id}") - Long id; - @Value("${system.admin.password}") - String password; - Long unValidId = 1000L; - String unValidPassword = "unValidPassword"; - @Value("${cookie.refresh.token.name}") - String refreshTokenName; - - @Autowired - SystemAdminAuthenticationFilter authenticationFilter; - @Autowired - private WebApplicationContext webApplicationContext; - @MockBean - RedisTemplate redisTemplate; - @MockBean - RedisRefreshTokenUtil redisRefreshTokenUtil; - @MockBean - RedisKeyValueAdapter keyValueAdapter; - - MockMvc mvc; - - - @BeforeEach - public void setUp() { - mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilter(authenticationFilter) - .build(); - } - - private String asJsonString(Object obj) throws JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.writeValueAsString(obj); - } - - - private SystemAdminLoginDto createUnValidSystemAdminAccount() { - return new SystemAdminLoginDto(unValidId, unValidPassword); - } - - private SystemAdminLoginDto createValidSystemAdminAccount() { - return new SystemAdminLoginDto(id, password); - - - } - - private MvcResult getValidSystemAdminUserResponse(SystemAdminLoginDto validUserDto) - throws Exception { - return mvc.perform(MockMvcRequestBuilders - .post("/admin/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(validUserDto))) - .andExpect(status().isOk()) - .andReturn(); - } - - - private void getUnValidSystemAdminUserResult(SystemAdminLoginDto unValidDto) - throws Exception { - System.out.println("dto:{}" + unValidDto.getId()); - mvc.perform(MockMvcRequestBuilders - .post("/admin/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(unValidDto))) - .andExpect(status().is4xxClientError()).andReturn(); - - } - - @DisplayName("잘못된 계정으로 로그인 시도") - @Test - void Login_WhenIdAndPasswordAreNotMatched_CatchBadCredentialException() - { - SystemAdminLoginDto dto = createUnValidSystemAdminAccount(); - assertThrows(SystemAdminAuthException.class, () -> { - getUnValidSystemAdminUserResult(dto); - }); - } - - - @DisplayName("유효한 계정으로 로그인시 JWT토큰 response에서 확인") - @Test - void Login_WhenIdAndPasswordAreNotMatched_JwtTokenInResponse() throws Exception { - SystemAdminLoginDto validDto = createValidSystemAdminAccount(); - MvcResult validUser = getValidSystemAdminUserResponse(validDto); - MockHttpServletResponse response = validUser.getResponse(); - System.out.println("response:{}" + response); - String authorizationHeader = response.getHeader("Authorization"); - assertNotNull(authorizationHeader); - } - - @DisplayName("유효한 계정으로 로그인시 RefreshToken Redis에서 존재 확인") - @Test - void Login_WhenIdAndPasswordAreNotMatched_RefreshTokenInRedis() throws Exception { - SystemAdminLoginDto validDto = createValidSystemAdminAccount(); - - Mockito.doNothing() - .when(redisRefreshTokenUtil).saveRefreshToken("100",null, 3660L); - - getValidSystemAdminUserResponse(validDto); - - } - - @DisplayName("유효한 계정으로 로그인시 RefreshToken Cookie에서 존재 확인") - @Test - void Login_WhenIdAndPasswordAreNotMatched_RefreshTokenInResponseCookie() throws Exception { - SystemAdminLoginDto validDto = createValidSystemAdminAccount(); - MvcResult validUser = getValidSystemAdminUserResponse(validDto); - assertNotNull(validUser.getResponse().getCookie(refreshTokenName)); - - } - - -} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index 4e617759..63fa1678 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -102,4 +102,10 @@ service: user: domain: "http://localhost:8082" +client: + redirect: + domain: http://localhost:3000/login/oauth +user: + info: + secret: user-secret-user-secret-user-secret-user-secret-user-secret