diff --git a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResource.java b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResource.java index 9e68e45..e9a82ac 100644 --- a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResource.java +++ b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResource.java @@ -12,6 +12,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -96,13 +97,14 @@ public class UserResource { } @DeleteMapping("{id}") + @PreAuthorize("hasAuthority('user:delete')") public HttpResponse deleteUser(@PathVariable long id) { userService.deleteUser(id); return HttpResponse.builder() .httpStatusCode(OK.value()) .httpStatus(OK) .reason(OK.getReasonPhrase()) - .message("User deleted successfully") + .message("User deleted successfully".toUpperCase()) .build(); } diff --git a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/exception/ExceptionHandling.java b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/exception/ExceptionHandling.java index 1885e50..b75f411 100644 --- a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/exception/ExceptionHandling.java +++ b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/exception/ExceptionHandling.java @@ -7,6 +7,7 @@ import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.Email import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.EmailNotFoundException; import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.UserNotFoundException; import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.UsernameExistsException; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; @@ -70,6 +71,13 @@ public class ExceptionHandling { return createHttpResponse(BAD_REQUEST, exception.getMessage()); } + @ExceptionHandler({ + EmptyResultDataAccessException.class + }) + public ResponseEntity emptyResultDataAccessExceptionHandler(EmptyResultDataAccessException exception) { + return createHttpResponse(BAD_REQUEST, "" + exception.getMessage()); + } + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public ResponseEntity methodNotSupportedException(HttpRequestMethodNotSupportedException exception) { HttpMethod supportedMethod = Objects.requireNonNull(exception.getSupportedHttpMethods()).iterator().next(); diff --git a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/common/BaseUserTest.java b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/common/BaseUserTest.java index 1f84943..0957de9 100644 --- a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/common/BaseUserTest.java +++ b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/common/BaseUserTest.java @@ -1,7 +1,6 @@ package net.shyshkin.study.fullstack.supportportal.backend.common; import com.github.javafaker.Faker; -import net.shyshkin.study.fullstack.supportportal.backend.domain.Role; import net.shyshkin.study.fullstack.supportportal.backend.domain.User; import net.shyshkin.study.fullstack.supportportal.backend.domain.dto.UserDto; import net.shyshkin.study.fullstack.supportportal.backend.repository.UserRepository; @@ -15,6 +14,7 @@ import java.util.UUID; import static net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant.DEFAULT_USER_IMAGE_PATH; import static net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant.USER_IMAGE_FILENAME; +import static net.shyshkin.study.fullstack.supportportal.backend.domain.Role.ROLE_ADMIN; @SpringBootTest @ActiveProfiles("local") @@ -43,7 +43,7 @@ public abstract class BaseUserTest { .lastLoginDate(LocalDateTime.now()) .lastLoginDateDisplay(LocalDateTime.now()) .role("ROLE_ADMIN") - .authorities(new String[]{"user:delete", "user:read"}) + .authorities(ROLE_ADMIN.getAuthorities()) .build(); } @@ -55,7 +55,7 @@ public abstract class BaseUserTest { .username(FAKER.name().username()) .isActive(true) .isNonLocked(true) - .role(Role.ROLE_ADMIN) + .role(ROLE_ADMIN) .build(); } diff --git a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceTest.java b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceTest.java index cd0e369..cbd6adb 100644 --- a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceTest.java +++ b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceTest.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import net.shyshkin.study.fullstack.supportportal.backend.common.BaseUserTest; import net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant; import net.shyshkin.study.fullstack.supportportal.backend.domain.HttpResponse; +import net.shyshkin.study.fullstack.supportportal.backend.domain.Role; import net.shyshkin.study.fullstack.supportportal.backend.domain.User; import net.shyshkin.study.fullstack.supportportal.backend.domain.UserPrincipal; import net.shyshkin.study.fullstack.supportportal.backend.domain.dto.UserDto; @@ -633,4 +634,91 @@ class UserResourceTest extends BaseUserTest { assertThat(Files.getLastModifiedTime(path).toInstant()).isCloseTo(Instant.now(), within(1, ChronoUnit.SECONDS)); } + @Nested + class DeleteUserTests { + + @BeforeEach + void setUp() { + user = userRepository.save(createRandomUser()); + } + + @Test + void deleteUser_ok_hasAuthority() { + + //given + User superAdmin = createRandomUser(); + superAdmin.setRole(Role.ROLE_SUPER_ADMIN.name()); + superAdmin.setAuthorities(Role.ROLE_SUPER_ADMIN.getAuthorities()); + String token = jwtTokenProvider.generateJwtToken(new UserPrincipal(superAdmin)); + + long id = user.getId(); + + //when + var requestEntity = RequestEntity.delete("/user/{id}", id) + .headers(headers -> headers.setBearerAuth(token)) + .build(); + var responseEntity = restTemplate.exchange(requestEntity, HttpResponse.class); + + //then + log.debug("Response Entity: {}", responseEntity); + assertThat(responseEntity.getStatusCode()).isEqualTo(OK); + assertThat(responseEntity.getBody()) + .isNotNull() + .hasNoNullFieldsOrProperties() + .hasFieldOrPropertyWithValue("httpStatus", OK) + .hasFieldOrPropertyWithValue("message", "USER DELETED SUCCESSFULLY"); + } + + @Test + void deleteUser_unauthorized_has_NO_Authority() { + + //given + User roleUser = createRandomUser(); + String token = jwtTokenProvider.generateJwtToken(new UserPrincipal(roleUser)); + + long id = user.getId(); + + //when + var requestEntity = RequestEntity.delete("/user/{id}", id) + .headers(headers -> headers.setBearerAuth(token)) + .build(); + var responseEntity = restTemplate.exchange(requestEntity, HttpResponse.class); + + //then + log.debug("Response Entity: {}", responseEntity); + assertThat(responseEntity.getStatusCode()).isEqualTo(FORBIDDEN); + assertThat(responseEntity.getBody()) + .isNotNull() + .hasNoNullFieldsOrProperties() + .hasFieldOrPropertyWithValue("httpStatus", FORBIDDEN) + .hasFieldOrPropertyWithValue("message", "YOU DO NOT HAVE ENOUGH PERMISSION"); + } + + @Test + void deleteUser_badRequest_absentId() { + + //given + User superAdmin = createRandomUser(); + superAdmin.setRole(Role.ROLE_SUPER_ADMIN.name()); + superAdmin.setAuthorities(Role.ROLE_SUPER_ADMIN.getAuthorities()); + String token = jwtTokenProvider.generateJwtToken(new UserPrincipal(superAdmin)); + + long id = Integer.MAX_VALUE; + + //when + var requestEntity = RequestEntity.delete("/user/{id}", id) + .headers(headers -> headers.setBearerAuth(token)) + .build(); + var responseEntity = restTemplate.exchange(requestEntity, HttpResponse.class); + + //then + log.debug("Response Entity: {}", responseEntity); + assertThat(responseEntity.getStatusCode()).isEqualTo(BAD_REQUEST); + assertThat(responseEntity.getBody()) + .isNotNull() + .hasNoNullFieldsOrProperties() + .hasFieldOrPropertyWithValue("httpStatus", BAD_REQUEST) + .hasFieldOrPropertyWithValue("message", "NO CLASS NET.SHYSHKIN.STUDY.FULLSTACK.SUPPORTPORTAL.BACKEND.DOMAIN.USER ENTITY WITH ID 2147483647 EXISTS!"); + } + } } \ No newline at end of file diff --git a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceUnSecureTest.java b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceUnSecureTest.java index 2f64786..c1e6dd3 100644 --- a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceUnSecureTest.java +++ b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceUnSecureTest.java @@ -547,38 +547,6 @@ class UserResourceUnSecureTest extends BaseUserTest { } } - @Nested - class DeleteUserTests { - - @BeforeEach - void setUp() { - user = userRepository - .findAll() - .stream() - .findAny() - .orElseGet(() -> userRepository.save(createRandomUser())); - } - - @Test - void deleteUser() { - - //given - long id = user.getId(); - - //when - var responseEntity = restTemplate.exchange("/user/{id}", HttpMethod.DELETE, null, HttpResponse.class, id); - - //then - log.debug("Response Entity: {}", responseEntity); - assertThat(responseEntity.getStatusCode()).isEqualTo(OK); - assertThat(responseEntity.getBody()) - .isNotNull() - .hasNoNullFieldsOrProperties() - .hasFieldOrPropertyWithValue("httpStatus", OK) - .hasFieldOrPropertyWithValue("message", "User deleted successfully"); - } - } - @Nested class UpdateProfileImageTests {