diff --git a/backend/src/main/java/com/festago/auth/application/AdminAuthService.java b/backend/src/main/java/com/festago/auth/application/AdminAuthService.java deleted file mode 100644 index 1a075f715..000000000 --- a/backend/src/main/java/com/festago/auth/application/AdminAuthService.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.festago.auth.application; - -import com.festago.admin.domain.Admin; -import com.festago.admin.repository.AdminRepository; -import com.festago.auth.domain.AuthPayload; -import com.festago.auth.domain.Role; -import com.festago.auth.dto.AdminLoginRequest; -import com.festago.auth.dto.AdminSignupRequest; -import com.festago.auth.dto.AdminSignupResponse; -import com.festago.common.exception.BadRequestException; -import com.festago.common.exception.ErrorCode; -import com.festago.common.exception.ForbiddenException; -import com.festago.common.exception.UnauthorizedException; -import java.util.Objects; -import lombok.RequiredArgsConstructor; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Deprecated(forRemoval = true) -@Service -@Transactional -@RequiredArgsConstructor -public class AdminAuthService { - - private final AuthProvider authProvider; - private final AdminRepository adminRepository; - private final PasswordEncoder passwordEncoder; - - @Transactional(readOnly = true) - public String login(AdminLoginRequest request) { - Admin admin = findAdminWithAuthenticate(request); - AuthPayload authPayload = new AuthPayload(admin.getId(), Role.ADMIN); - return authProvider.provide(authPayload); - } - - private Admin findAdminWithAuthenticate(AdminLoginRequest request) { - return adminRepository.findByUsername(request.username()) - .filter(admin -> passwordEncoder.matches(request.password(), admin.getPassword())) - .orElseThrow(() -> new UnauthorizedException(ErrorCode.INCORRECT_PASSWORD_OR_ACCOUNT)); - } - - public void initializeRootAdmin(String password) { - adminRepository.findByUsername(Admin.ROOT_ADMIN_NAME).ifPresentOrElse(admin -> { - throw new BadRequestException(ErrorCode.DUPLICATE_ACCOUNT_USERNAME); - }, () -> adminRepository.save(new Admin(Admin.ROOT_ADMIN_NAME, passwordEncoder.encode(password)))); - } - - public AdminSignupResponse signup(Long adminId, AdminSignupRequest request) { - validateRootAdmin(adminId); - String username = request.username(); - String password = passwordEncoder.encode(request.password()); - validateExistsUsername(username); - Admin admin = adminRepository.save(new Admin(username, password)); - return new AdminSignupResponse(admin.getUsername()); - } - - private void validateExistsUsername(String username) { - if (adminRepository.existsByUsername(username)) { - throw new BadRequestException(ErrorCode.DUPLICATE_ACCOUNT_USERNAME); - } - } - - private void validateRootAdmin(Long adminId) { - adminRepository.findById(adminId) - .map(Admin::getUsername) - .filter(username -> Objects.equals(username, Admin.ROOT_ADMIN_NAME)) - .ifPresentOrElse(username -> { - }, () -> { - throw new ForbiddenException(ErrorCode.NOT_ENOUGH_PERMISSION); - }); - } -} diff --git a/backend/src/main/java/com/festago/auth/dto/AdminLoginRequest.java b/backend/src/main/java/com/festago/auth/dto/AdminLoginRequest.java deleted file mode 100644 index f5a63b974..000000000 --- a/backend/src/main/java/com/festago/auth/dto/AdminLoginRequest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.festago.auth.dto; - -import jakarta.validation.constraints.NotBlank; - -@Deprecated(forRemoval = true) -public record AdminLoginRequest( - @NotBlank(message = "username은 공백일 수 없습니다.") - String username, - @NotBlank(message = "password는 공백일 수 없습니다.") - String password -) { - -} diff --git a/backend/src/main/java/com/festago/auth/dto/AdminSignupRequest.java b/backend/src/main/java/com/festago/auth/dto/AdminSignupRequest.java deleted file mode 100644 index 3e9210746..000000000 --- a/backend/src/main/java/com/festago/auth/dto/AdminSignupRequest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.festago.auth.dto; - -import jakarta.validation.constraints.NotBlank; - -@Deprecated(forRemoval = true) -public record AdminSignupRequest( - @NotBlank(message = "username은 공백일 수 없습니다.") - String username, - @NotBlank(message = "password는 공백일 수 없습니다.") - String password -) { - -} diff --git a/backend/src/main/java/com/festago/auth/dto/AdminSignupResponse.java b/backend/src/main/java/com/festago/auth/dto/AdminSignupResponse.java deleted file mode 100644 index 26502c861..000000000 --- a/backend/src/main/java/com/festago/auth/dto/AdminSignupResponse.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.festago.auth.dto; - -@Deprecated(forRemoval = true) -public record AdminSignupResponse( - String username -) { - -} diff --git a/backend/src/main/java/com/festago/auth/presentation/AdminAuthController.java b/backend/src/main/java/com/festago/auth/presentation/AdminAuthController.java deleted file mode 100644 index 1646b36d6..000000000 --- a/backend/src/main/java/com/festago/auth/presentation/AdminAuthController.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.festago.auth.presentation; - -import com.festago.auth.annotation.Admin; -import com.festago.auth.application.AdminAuthService; -import com.festago.auth.dto.AdminLoginRequest; -import com.festago.auth.dto.AdminSignupRequest; -import com.festago.auth.dto.AdminSignupResponse; -import com.festago.auth.dto.RootAdminInitializeRequest; -import io.swagger.v3.oas.annotations.Hidden; -import jakarta.validation.Valid; -import java.time.Duration; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseCookie; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@Deprecated(forRemoval = true) -@RestController -@RequestMapping("/admin/api") -@Hidden -@RequiredArgsConstructor -public class AdminAuthController { - - private final AdminAuthService adminAuthService; - - @PostMapping("/login") - public ResponseEntity login(@RequestBody @Valid AdminLoginRequest request) { - String token = adminAuthService.login(request); - return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, createLoginCookie(token)) - .build(); - } - - private String createLoginCookie(String token) { - return ResponseCookie.from("token", token) - .httpOnly(true) - .secure(true) - .sameSite("None") - .path("/") - .build().toString(); - } - - /** - * 클라이언트 측에서 httpOnly 쿠키를 조작할 수 없기 때문에, 서버 측에서 쿠키를 관리해주어야 함 - */ - @GetMapping("/logout") - public ResponseEntity logout() { - return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, createLogoutCookie()) - .build(); - } - - private String createLogoutCookie() { - return ResponseCookie.from("token", "") - .httpOnly(true) - .secure(true) - .sameSite("None") - .path("/") - .maxAge(Duration.ZERO) - .build().toString(); - } - - @PostMapping("/signup") - public ResponseEntity signupAdminAccount(@RequestBody @Valid AdminSignupRequest request, - @Admin Long adminId) { - AdminSignupResponse response = adminAuthService.signup(adminId, request); - return ResponseEntity.ok() - .body(response); - } - - @PostMapping("/initialize") - public ResponseEntity initializeRootAdmin(@RequestBody @Valid RootAdminInitializeRequest request) { - adminAuthService.initializeRootAdmin(request.password()); - return ResponseEntity.ok() - .build(); - } -} diff --git a/backend/src/main/java/com/festago/stage/domain/Stage.java b/backend/src/main/java/com/festago/stage/domain/Stage.java index 0c2d5ee64..a60facbaa 100644 --- a/backend/src/main/java/com/festago/stage/domain/Stage.java +++ b/backend/src/main/java/com/festago/stage/domain/Stage.java @@ -92,14 +92,6 @@ public LocalDateTime getStartTime() { return startTime; } - /** - * API 일부에 사용되는 곳이 있기 때문에 deprecated 문자열을 반환하도록 처리 - */ - @Deprecated(forRemoval = true) - public String getLineUp() { - return "deprecated"; - } - public LocalDateTime getTicketOpenTime() { return ticketOpenTime; } diff --git a/backend/src/test/java/com/festago/acceptance/steps/AdminStepDefinitions.java b/backend/src/test/java/com/festago/acceptance/steps/AdminStepDefinitions.java index 0485d0d2b..1b03adc9c 100644 --- a/backend/src/test/java/com/festago/acceptance/steps/AdminStepDefinitions.java +++ b/backend/src/test/java/com/festago/acceptance/steps/AdminStepDefinitions.java @@ -1,8 +1,8 @@ package com.festago.acceptance.steps; import com.festago.acceptance.CucumberClient; -import com.festago.auth.application.AdminAuthService; -import com.festago.auth.dto.AdminLoginRequest; +import com.festago.auth.application.command.AdminAuthCommandService; +import com.festago.auth.dto.command.AdminLoginCommand; import io.cucumber.java.en.Given; import org.springframework.beans.factory.annotation.Autowired; @@ -12,12 +12,12 @@ public class AdminStepDefinitions { CucumberClient cucumberClient; @Autowired - AdminAuthService adminAuthService; + AdminAuthCommandService adminAuthCommandService; @Given("어드민 계정으로 로그인한다.") public void loginAdmin() { - adminAuthService.initializeRootAdmin("1234"); - String token = adminAuthService.login(new AdminLoginRequest("admin", "1234")); - cucumberClient.setToken(token); + adminAuthCommandService.initializeRootAdmin("1234"); + var adminLoginResult = adminAuthCommandService.login(new AdminLoginCommand("admin", "1234")); + cucumberClient.setToken(adminLoginResult.accessToken()); } } diff --git a/backend/src/test/java/com/festago/auth/application/AdminAuthServiceTest.java b/backend/src/test/java/com/festago/auth/application/AdminAuthServiceTest.java deleted file mode 100644 index 2897abf38..000000000 --- a/backend/src/test/java/com/festago/auth/application/AdminAuthServiceTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.festago.auth.application; - -import static com.festago.common.exception.ErrorCode.DUPLICATE_ACCOUNT_USERNAME; -import static com.festago.common.exception.ErrorCode.INCORRECT_PASSWORD_OR_ACCOUNT; -import static com.festago.common.exception.ErrorCode.NOT_ENOUGH_PERMISSION; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.BDDMockito.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.mock; - -import com.festago.admin.domain.Admin; -import com.festago.admin.repository.AdminRepository; -import com.festago.admin.repository.MemoryAdminRepository; -import com.festago.auth.dto.AdminLoginRequest; -import com.festago.auth.dto.AdminSignupRequest; -import com.festago.auth.dto.AdminSignupResponse; -import com.festago.common.exception.BadRequestException; -import com.festago.common.exception.ForbiddenException; -import com.festago.common.exception.UnauthorizedException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayNameGeneration; -import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.springframework.security.crypto.factory.PasswordEncoderFactories; - -@Deprecated(forRemoval = true) -@DisplayNameGeneration(ReplaceUnderscores.class) -@SuppressWarnings("NonAsciiCharacters") -class AdminAuthServiceTest { - - AdminRepository adminRepository; - - AuthProvider authProvider = mock(AuthProvider.class); - - AdminAuthService adminAuthService; - - @BeforeEach - void setUp() { - adminRepository = new MemoryAdminRepository(); - adminAuthService = new AdminAuthService(authProvider, adminRepository, - PasswordEncoderFactories.createDelegatingPasswordEncoder()); - } - - @Nested - class 로그인 { - - @Test - void 계정이_없으면_예외() { - // given - AdminLoginRequest request = new AdminLoginRequest("admin", "password"); - - // when & then - assertThatThrownBy(() -> adminAuthService.login(request)) - .isInstanceOf(UnauthorizedException.class) - .hasMessage(INCORRECT_PASSWORD_OR_ACCOUNT.getMessage()); - } - - @Test - void 비밀번호가_틀리면_예외() { - // given - adminRepository.save(new Admin("admin", "{noop}password")); - AdminLoginRequest request = new AdminLoginRequest("admin", "admin"); - - // when & then - assertThatThrownBy(() -> adminAuthService.login(request)) - .isInstanceOf(UnauthorizedException.class) - .hasMessage(INCORRECT_PASSWORD_OR_ACCOUNT.getMessage()); - } - - @Test - void 성공() { - // given - adminRepository.save(new Admin("admin", "{noop}password")); - AdminLoginRequest request = new AdminLoginRequest("admin", "password"); - given(authProvider.provide(any())) - .willReturn("token"); - - // when - String token = adminAuthService.login(request); - - // then - assertThat(token).isEqualTo("token"); - } - } - - @Nested - class 가입 { - - @Test - void 닉네임이_중복이면_예외() { - // given - Admin rootAdmin = adminRepository.save(new Admin("admin", "{noop}password")); - AdminSignupRequest request = new AdminSignupRequest("admin", "password"); - - // when & then - Long rootAdminId = rootAdmin.getId(); - assertThatThrownBy(() -> adminAuthService.signup(rootAdminId, request)) - .isInstanceOf(BadRequestException.class) - .hasMessage(DUPLICATE_ACCOUNT_USERNAME.getMessage()); - } - - @Test - void Root_어드민이_아니면_예외() { - // given - Admin admin = adminRepository.save(new Admin("glen", "{noop}password")); - AdminSignupRequest request = new AdminSignupRequest("newAdmin", "password"); - - // when & then - Long adminId = admin.getId(); - assertThatThrownBy(() -> adminAuthService.signup(adminId, request)) - .isInstanceOf(ForbiddenException.class) - .hasMessage(NOT_ENOUGH_PERMISSION.getMessage()); - } - - @Test - void 성공() { - // given - Admin rootAdmin = adminRepository.save(new Admin("admin", "{noop}password")); - AdminSignupRequest request = new AdminSignupRequest("newAdmin", "password"); - - // when - AdminSignupResponse response = adminAuthService.signup(rootAdmin.getId(), request); - - // then - assertThat(adminRepository.existsByUsername(response.username())).isTrue(); - } - } -} diff --git a/backend/src/test/java/com/festago/auth/presentation/AdminAuthControllerTest.java b/backend/src/test/java/com/festago/auth/presentation/AdminAuthControllerTest.java deleted file mode 100644 index 99b8416a8..000000000 --- a/backend/src/test/java/com/festago/auth/presentation/AdminAuthControllerTest.java +++ /dev/null @@ -1,199 +0,0 @@ -package com.festago.auth.presentation; - -import static org.mockito.BDDMockito.any; -import static org.mockito.BDDMockito.anyLong; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.auth.application.AdminAuthService; -import com.festago.auth.domain.Role; -import com.festago.auth.dto.AdminLoginRequest; -import com.festago.auth.dto.AdminSignupRequest; -import com.festago.auth.dto.AdminSignupResponse; -import com.festago.auth.dto.RootAdminInitializeRequest; -import com.festago.support.CustomWebMvcTest; -import com.festago.support.WithMockAuth; -import jakarta.servlet.http.Cookie; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.DisplayNameGeneration; -import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; - -@Deprecated(forRemoval = true) -@CustomWebMvcTest -@DisplayNameGeneration(ReplaceUnderscores.class) -@SuppressWarnings("NonAsciiCharacters") -class AdminAuthControllerTest { - - private static final Cookie AUTH_TOKEN = new Cookie("token", "token"); - - @Autowired - MockMvc mockMvc; - - @Autowired - ObjectMapper objectMapper; - - @Autowired - AdminAuthService adminAuthService; - - @Nested - class 어드민_로그인 { - - final String uri = "/admin/api/login"; - - @Nested - @DisplayName("POST " + uri) - class 올바른_주소로 { - - @Test - void 요청을_보내면_200_응답과_로그인_토큰이_담긴_쿠키가_반환된다() throws Exception { - // given - var request = new AdminLoginRequest("admin", "1234"); - given(adminAuthService.login(any(AdminLoginRequest.class))) - .willReturn("token"); - - // when & then - mockMvc.perform(post(uri) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(cookie().exists(AUTH_TOKEN.getName())) - .andExpect(cookie().path(AUTH_TOKEN.getName(), "/")) - .andExpect(cookie().secure(AUTH_TOKEN.getName(), true)) - .andExpect(cookie().httpOnly(AUTH_TOKEN.getName(), true)) - .andExpect(cookie().sameSite(AUTH_TOKEN.getName(), "None")); - } - } - } - - @Nested - class 어드민_로그아웃 { - - final String uri = "/admin/api/logout"; - - @Nested - @DisplayName("GET " + uri) - class 올바른_주소로 { - - @Test - @WithMockAuth(role = Role.ADMIN) - void 요청을_보내면_200_응답과_비어있는_값의_로그인_토큰이_담긴_쿠기가_반환된다() throws Exception { - // when & then - mockMvc.perform(get(uri) - .cookie(AUTH_TOKEN)) - .andExpect(status().isOk()) - .andExpect(cookie().exists(AUTH_TOKEN.getName())) - .andExpect(cookie().value(AUTH_TOKEN.getName(), "")) - .andExpect(cookie().path(AUTH_TOKEN.getName(), "/")) - .andExpect(cookie().secure(AUTH_TOKEN.getName(), true)) - .andExpect(cookie().httpOnly(AUTH_TOKEN.getName(), true)) - .andExpect(cookie().sameSite(AUTH_TOKEN.getName(), "None")); - } - - @Test - void 토큰_없이_보내면_401_응답이_반환된다() throws Exception { - // when & then - mockMvc.perform(get(uri)) - .andExpect(status().isUnauthorized()); - } - - @Test - @WithMockAuth(role = Role.MEMBER) - void 토큰의_권한이_Admin이_아니면_404_응답이_반환된다() throws Exception { - // when & then - mockMvc.perform(get(uri) - .cookie(AUTH_TOKEN)) - .andExpect(status().isNotFound()); - } - } - } - - @Nested - class 어드민_회원가입 { - - final String uri = "/admin/api/signup"; - - @Nested - @DisplayName("POST " + uri) - class 올바른_주소로 { - - @Test - @WithMockAuth(role = Role.ADMIN) - void 요청을_보내면_200_응답과_생성한_계정이_반환된다() throws Exception { - var request = new AdminSignupRequest("newAdmin", "1234"); - var response = new AdminSignupResponse("newAdmin"); - given(adminAuthService.signup(anyLong(), any(AdminSignupRequest.class))) - .willReturn(response); - - // when & then - mockMvc.perform(post(uri) - .cookie(AUTH_TOKEN) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.username").value("newAdmin")); - } - - @Test - void 토큰_없이_보내면_401_응답이_반환된다() throws Exception { - // when & then - mockMvc.perform(post(uri)) - .andExpect(status().isUnauthorized()); - } - - @Test - @WithMockAuth(role = Role.MEMBER) - void 토큰의_권한이_Admin이_아니면_404_응답이_반환된다() throws Exception { - // when & then - mockMvc.perform(post(uri) - .cookie(AUTH_TOKEN)) - .andExpect(status().isNotFound()); - } - } - } - - @Nested - class 루트_어드민_활성화 { - - final String uri = "/admin/api/initialize"; - - @Nested - @DisplayName("POST " + uri) - class 올바른_주소로 { - - @Test - void 요청을_보내면_200_응답이_반환된다() throws Exception { - // given - var request = new RootAdminInitializeRequest("1234"); - - // when & then - mockMvc.perform(post(uri) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - } - - @Test - @WithMockAuth(role = Role.ANONYMOUS) - void 권한이_없어도_200_응답이_반환된다() throws Exception { - // given - var request = new RootAdminInitializeRequest("1234"); - - // when & then - mockMvc.perform(post(uri) - .content(objectMapper.writeValueAsString(request)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - } - } - } -}