BAEL-1918 Spring StrictHttpFirewall and RequestRejectedException (#11265)
* BAEL-1918: Added code to for RequestRejectedException and StrictHttpFirewall tutorial * BAEL-1918: Added code to for RequestRejectedException and StrictHttpFirewall tutorial * BAEL:1918 - Modifed the code to accomodate comments from Michal * BAEL:1918 - Modifed the code to accomodate comments from Michal
This commit is contained in:
		
							parent
							
								
									102f09fc6c
								
							
						
					
					
						commit
						be966d6d62
					
				| @ -1,7 +1,7 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||
|     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <artifactId>spring-security-web-boot-3</artifactId> | ||||
|     <version>0.0.1-SNAPSHOT</version> | ||||
| @ -25,6 +25,20 @@ | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-web</artifactId> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-test</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.commons</groupId> | ||||
|             <artifactId>commons-lang3</artifactId> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.security</groupId> | ||||
|             <artifactId>spring-security-test</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,15 @@ | ||||
| package com.baeldung.httpfirewall; | ||||
| 
 | ||||
| import org.springframework.boot.SpringApplication; | ||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||
| 
 | ||||
| @SpringBootApplication | ||||
| public class HttpFirewallApplication { | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
|         SpringApplication application = new SpringApplication(HttpFirewallApplication.class); | ||||
|         application.setAdditionalProfiles("httpfirewall"); | ||||
|         application.run(args); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,48 @@ | ||||
| package com.baeldung.httpfirewall; | ||||
| 
 | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||||
| import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | ||||
| import org.springframework.security.web.firewall.HttpFirewall; | ||||
| import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler; | ||||
| import org.springframework.security.web.firewall.RequestRejectedHandler; | ||||
| import org.springframework.security.web.firewall.StrictHttpFirewall; | ||||
| 
 | ||||
| import java.util.Arrays; | ||||
| 
 | ||||
| @Configuration | ||||
| public class HttpFirewallConfiguration extends WebSecurityConfigurerAdapter { | ||||
| 
 | ||||
|     @Override | ||||
|     protected void configure(HttpSecurity http) throws Exception { | ||||
|         //@formatter:off | ||||
|         http | ||||
|           .csrf() | ||||
|           .disable() | ||||
|           .authorizeRequests() | ||||
|           .antMatchers("/error") | ||||
|           .permitAll() | ||||
|           .anyRequest() | ||||
|           .authenticated() | ||||
|           .and() | ||||
|           .httpBasic(); | ||||
|         //@formatter:on | ||||
|     } | ||||
| 
 | ||||
|     @Bean | ||||
|     public HttpFirewall configureFirewall() { | ||||
|         StrictHttpFirewall strictHttpFirewall = new StrictHttpFirewall(); | ||||
|         strictHttpFirewall.setAllowedHttpMethods(Arrays.asList("GET", "POST", "DELETE", "OPTIONS")); // Allow only HTTP GET, POST, DELETE and OPTIONS methods | ||||
|         return strictHttpFirewall; | ||||
|     } | ||||
| 
 | ||||
|     /* | ||||
|      Use this bean if you are using Spring Security 5.4 and above | ||||
|      */ | ||||
|     @Bean | ||||
|     public RequestRejectedHandler requestRejectedHandler() { | ||||
|         return new HttpStatusRequestRejectedHandler(); // Default status code is 400. Can be customized | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| package com.baeldung.httpfirewall.api; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.model.Response; | ||||
| import com.baeldung.httpfirewall.model.User; | ||||
| import com.baeldung.httpfirewall.service.UserServiceImpl; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.springframework.http.HttpStatus; | ||||
| import org.springframework.http.ResponseEntity; | ||||
| import org.springframework.web.bind.annotation.DeleteMapping; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| 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.RequestMapping; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
| import org.springframework.web.server.ResponseStatusException; | ||||
| 
 | ||||
| import java.net.URI; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.UUID; | ||||
| 
 | ||||
| @RestController | ||||
| @RequestMapping("/api/v1/users") | ||||
| public class UserApi { | ||||
| 
 | ||||
|     private final UserServiceImpl userServiceImpl; | ||||
| 
 | ||||
|     public UserApi(UserServiceImpl userServiceImpl) { | ||||
|         this.userServiceImpl = userServiceImpl; | ||||
|     } | ||||
| 
 | ||||
|     @PostMapping | ||||
|     public ResponseEntity<Response> createUser(@RequestBody User user) { | ||||
|         if (StringUtils.isBlank(user.getId())) { | ||||
|             user.setId(UUID.randomUUID().toString()); | ||||
|         } | ||||
|         userServiceImpl.saveUser(user); | ||||
|         Response response = new Response(HttpStatus.CREATED.value(), "User created successfully", System.currentTimeMillis()); | ||||
|         URI location = URI.create("/users/" + user.getId()); | ||||
|         return ResponseEntity.created(location).body(response); | ||||
|     } | ||||
| 
 | ||||
|     @GetMapping("/{userId}") | ||||
|     public User getUser(@PathVariable("userId") String userId) { | ||||
|         return userServiceImpl.findById(userId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No user exists with the given Id")); | ||||
|     } | ||||
| 
 | ||||
|     @GetMapping() | ||||
|     public List<User> getAllUsers() { | ||||
|         return userServiceImpl.findAll().orElse(new ArrayList<>()); | ||||
|     } | ||||
| 
 | ||||
|     @DeleteMapping("/{userId}") | ||||
|     public ResponseEntity<Response> deleteUser(@PathVariable("userId") String userId) { | ||||
|         userServiceImpl.deleteUser(userId); | ||||
|         return ResponseEntity.ok(new Response(200, "The user has been deleted successfully", System.currentTimeMillis())); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,65 @@ | ||||
| package com.baeldung.httpfirewall.dao; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.model.User; | ||||
| import org.springframework.stereotype.Repository; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Optional; | ||||
| 
 | ||||
| @Repository | ||||
| public class InMemoryUserDao { | ||||
|     private Map<String, User> map = new HashMap<>(); | ||||
| 
 | ||||
|     /** | ||||
|      * Persists the user. The user is store in an In-Memory store (a HashMap) | ||||
|      * The default implementation is an In-Memory persistence | ||||
|      * @param user The user that should be persisted | ||||
|      */ | ||||
| 
 | ||||
|     public void save(User user) { | ||||
|         map.put(user.getId(), user); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Finds the user from the in-memory data store. | ||||
|      * The default implementation is an In-Memory persistence | ||||
|      * | ||||
|      * @param userId The ID of the user that has to be fetched | ||||
|      * @return An optional of the requested user | ||||
|      */ | ||||
|     public Optional<User> findById(String userId) { | ||||
|         return Optional.ofNullable(map.get(userId)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Finds all the users from the in-memory data store | ||||
|      * The default implementation is an In-Memory persistence | ||||
|      */ | ||||
| 
 | ||||
|     public Optional<List<User>> findAll() { | ||||
|         return Optional.of(new ArrayList<>(map.values())); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Delete the user from the data store | ||||
|      * The default implementation is an In-Memory persistence | ||||
|      * @param userId The user that has to be deleted | ||||
|      */ | ||||
| 
 | ||||
|     public void delete(String userId) { | ||||
|         map.remove(userId); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks if the user exists | ||||
|      * The default implementation is an In-Memory persistence | ||||
|      * @param userId The user that has to be checked for | ||||
|      */ | ||||
| 
 | ||||
|     public boolean isExists(String userId) { | ||||
|         return map.containsKey(userId); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package com.baeldung.httpfirewall.model; | ||||
| 
 | ||||
| public class Response { | ||||
|     private int code; | ||||
|     private String message; | ||||
|     private long timestamp; | ||||
| 
 | ||||
|     public Response() { | ||||
|     } | ||||
| 
 | ||||
|     public Response(int code, String message, long timestamp) { | ||||
|         this.code = code; | ||||
|         this.message = message; | ||||
|         this.timestamp = timestamp; | ||||
|     } | ||||
| 
 | ||||
|     public int getCode() { | ||||
|         return code; | ||||
|     } | ||||
| 
 | ||||
|     public void setCode(int code) { | ||||
|         this.code = code; | ||||
|     } | ||||
| 
 | ||||
|     public String getMessage() { | ||||
|         return message; | ||||
|     } | ||||
| 
 | ||||
|     public void setMessage(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
| 
 | ||||
|     public long getTimestamp() { | ||||
|         return timestamp; | ||||
|     } | ||||
| 
 | ||||
|     public void setTimestamp(long timestamp) { | ||||
|         this.timestamp = timestamp; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| package com.baeldung.httpfirewall.model; | ||||
| 
 | ||||
| public class User { | ||||
|     private String id; | ||||
|     private String username; | ||||
|     private String email; | ||||
| 
 | ||||
|     public User() { | ||||
|     } | ||||
| 
 | ||||
|     public User(String id, String username, String email) { | ||||
|         this.id = id; | ||||
|         this.username = username; | ||||
|         this.email = email; | ||||
|     } | ||||
| 
 | ||||
|     public String getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public void setId(String id) { | ||||
|         this.id = id; | ||||
|     } | ||||
| 
 | ||||
|     public String getUsername() { | ||||
|         return username; | ||||
|     } | ||||
| 
 | ||||
|     public void setUsername(String username) { | ||||
|         this.username = username; | ||||
|     } | ||||
| 
 | ||||
|     public String getEmail() { | ||||
|         return email; | ||||
|     } | ||||
| 
 | ||||
|     public void setEmail(String email) { | ||||
|         this.email = email; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,51 @@ | ||||
| package com.baeldung.httpfirewall.service; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.dao.InMemoryUserDao; | ||||
| import com.baeldung.httpfirewall.model.User; | ||||
| import org.springframework.stereotype.Service; | ||||
| 
 | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| 
 | ||||
| @Service | ||||
| public class UserServiceImpl { | ||||
| 
 | ||||
|     private final InMemoryUserDao inMemoryUserDao; | ||||
| 
 | ||||
|     public UserServiceImpl(InMemoryUserDao inMemoryUserDao) { | ||||
|         this.inMemoryUserDao = inMemoryUserDao; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a user. Checks if the user already exists and then persists the user | ||||
|      * @param user The user that is to be persisted into the store | ||||
|      */ | ||||
|     public void saveUser(User user) { | ||||
|         inMemoryUserDao.save(user); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get a user. Returns a user | ||||
|      * | ||||
|      * @param userId The user that has to be fetched form the repository | ||||
|      */ | ||||
|     public Optional<User> findById(String userId) { | ||||
|         return inMemoryUserDao.findById(userId); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Fetch all the users in the store | ||||
|      * @return A list of all the users | ||||
|      */ | ||||
|     public Optional<List<User>> findAll() { | ||||
|         return inMemoryUserDao.findAll(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Delete the user with a given id | ||||
|      * @param userId The identifier of the user | ||||
|      */ | ||||
|     public void deleteUser(String userId) { | ||||
|         inMemoryUserDao.delete(userId); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,2 @@ | ||||
| spring.security.user.name=user | ||||
| spring.security.user.password=password | ||||
| @ -0,0 +1,114 @@ | ||||
| package com.baeldung.httpfirewall.api; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.model.User; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.service.UserServiceImpl; | ||||
| import com.baeldung.httpfirewall.utility.UserTestUtility; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.DisplayName; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||||
| import org.springframework.boot.test.context.SpringBootTest; | ||||
| import org.springframework.http.HttpStatus; | ||||
| import org.springframework.security.test.context.support.WithMockUser; | ||||
| import org.springframework.test.web.servlet.MockMvc; | ||||
| import org.springframework.test.web.servlet.MvcResult; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
| import static org.junit.jupiter.api.Assertions.assertNotNull; | ||||
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; | ||||
| 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.MockMvcResultHandlers.print; | ||||
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; | ||||
| 
 | ||||
| @SpringBootTest | ||||
| @AutoConfigureMockMvc | ||||
| @DisplayName("User API Live Tests") | ||||
| class UserApiLiveTest { | ||||
| 
 | ||||
|     private final String userId = "1"; | ||||
| 
 | ||||
|     @Autowired | ||||
|     private MockMvc mockMvc; | ||||
|     @Autowired | ||||
|     private ObjectMapper objectMapper; | ||||
| 
 | ||||
|     @BeforeEach | ||||
|     void setup() throws Exception { | ||||
|         //@formatter:off | ||||
|         mockMvc | ||||
|           .perform(post("/api/v1/users") | ||||
|             .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithId(userId))) | ||||
|             .contentType("application/json")); | ||||
|         //@formatter:on | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("LiveTest User Creation") | ||||
|     void givenCredentials_whenHttpPost_thenReturn201() throws Exception { | ||||
|         // @formatter:off | ||||
|         MvcResult result = mockMvc | ||||
|           .perform(post("/api/v1/users") | ||||
|             .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithId("200"))) | ||||
|             .contentType("application/json")) | ||||
|           .andDo(print()) | ||||
|           .andExpect(header().exists("Location")).andReturn(); | ||||
| 
 | ||||
|         assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); | ||||
|         // @formatter:on | ||||
|         mockMvc.perform(delete("/api/v1/users/" + 200).contentType("application/json")); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("LiveTest Get User") | ||||
|     void givenCredentials_whenHttpGetById_thenReturnUser() throws Exception { | ||||
|         // @formatter:off | ||||
|         MvcResult result=mockMvc | ||||
|           .perform(get("/api/v1/users/"+userId) | ||||
|             .contentType("application/json")).andReturn(); | ||||
|         // @formatter:on | ||||
|         assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); | ||||
|         assertNotNull(result.getResponse()); | ||||
|         assertEquals(userId, objectMapper.readValue(result.getResponse().getContentAsString(), User.class).getId()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("LiveTest Get All Users") | ||||
|     void givenCredentials_whenHttpGet_thenReturnAllUsers() throws Exception { | ||||
|         // @formatter:off | ||||
|         MvcResult result=mockMvc | ||||
|           .perform(get("/api/v1/users/") | ||||
|             .contentType("application/json")).andReturn(); | ||||
|         // @formatter:on | ||||
|         assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); | ||||
|         assertNotNull(result.getResponse()); | ||||
|         assertNotNull(result.getResponse().getContentAsString()); | ||||
| 
 | ||||
|         List<User> users = objectMapper.readValue(result.getResponse().getContentAsString(), objectMapper.getTypeFactory().constructCollectionType(List.class, User.class)); | ||||
| 
 | ||||
|         assertEquals(1, users.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("LiveTest Delete User") | ||||
|     void givenCredentials_whenHttpDelete_thenDeleteUser() throws Exception { | ||||
|         // @formatter:off | ||||
|         MvcResult result=mockMvc | ||||
|           .perform(delete("/api/v1/users/"+userId) | ||||
|             .contentType("application/json")).andReturn(); | ||||
|         // @formatter:on | ||||
|         assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); | ||||
|         assertNotNull(result.getResponse()); | ||||
|         assertNotNull(result.getResponse().getContentAsString()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,161 @@ | ||||
| package com.baeldung.httpfirewall.api; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.model.User; | ||||
| import com.baeldung.httpfirewall.service.UserServiceImpl; | ||||
| import com.baeldung.httpfirewall.utility.UserTestUtility; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import org.junit.jupiter.api.DisplayName; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | ||||
| import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; | ||||
| import org.springframework.boot.test.mock.mockito.MockBean; | ||||
| import org.springframework.http.HttpStatus; | ||||
| import org.springframework.security.test.context.support.WithMockUser; | ||||
| import org.springframework.test.web.servlet.MockMvc; | ||||
| import org.springframework.test.web.servlet.MvcResult; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
| import static org.junit.jupiter.api.Assertions.assertNotNull; | ||||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
| import static org.mockito.Mockito.doNothing; | ||||
| import static org.mockito.Mockito.when; | ||||
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; | ||||
| 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.MockMvcResultHandlers.print; | ||||
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; | ||||
| 
 | ||||
| @WebMvcTest | ||||
| @AutoConfigureMockMvc | ||||
| @DisplayName("User API Unit Tests") | ||||
| class UserApiUnitTest { | ||||
| 
 | ||||
|     @Autowired | ||||
|     private MockMvc mockMvc; | ||||
| 
 | ||||
|     @MockBean | ||||
|     private UserServiceImpl userService; | ||||
| 
 | ||||
|     @Autowired | ||||
|     private ObjectMapper objectMapper; | ||||
| 
 | ||||
|     @Test | ||||
|     @DisplayName("Test to Check Authentication") | ||||
|     void whenNoAuthentication_thenThrow401() throws Exception { | ||||
|         // @formatter:off | ||||
|         MvcResult result = mockMvc | ||||
|           .perform(post("/api/v1/users") | ||||
|             .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) | ||||
|             .contentType("application/json")) | ||||
|           .andReturn(); | ||||
|         assertEquals(HttpStatus.UNAUTHORIZED.value(), result.getResponse().getStatus()); | ||||
|         // @formatter:off | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("Test Malicious URL") | ||||
|     void givenCredentials_whenMaliciousUrl_thenThrowRequestRejectedException() throws Exception { | ||||
|         // @formatter:off | ||||
|         MvcResult result = mockMvc | ||||
|           .perform(post("/api/v1\\users") | ||||
|             .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) | ||||
|             .contentType("application/json")) | ||||
|           .andDo(print()) | ||||
|           .andReturn(); | ||||
|         assertEquals(HttpStatus.BAD_REQUEST.value(), result.getResponse().getStatus()); | ||||
|         // @formatter:on | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("Test User Create") | ||||
|     void givenCredentials_whenHttpPost_thenReturn201() throws Exception { | ||||
|         // @formatter:off | ||||
|         doNothing().when(userService).saveUser(new User()); | ||||
| 
 | ||||
|         MvcResult result=mockMvc | ||||
|           .perform(post("/api/v1/users") | ||||
|             .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) | ||||
|             .contentType("application/json")) | ||||
|           .andDo(print()) | ||||
|           .andExpect(header().exists("Location")).andReturn(); | ||||
|         assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); | ||||
|         // @formatter:on | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("Test User Create Without ID") | ||||
|     void givenCredentials_whenHttpPostWithId_thenReturn201() throws Exception { | ||||
|         // @formatter:off | ||||
|        doNothing().when(userService).saveUser(new User()); | ||||
| 
 | ||||
|         MvcResult result = mockMvc | ||||
|           .perform(post("/api/v1/users") | ||||
|             .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithoutId())) | ||||
|             .contentType("application/json")) | ||||
|           .andDo(print()) | ||||
|           .andExpect(header().exists("Location")).andReturn(); | ||||
|         assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); | ||||
|         // @formatter:on | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("Test Get User") | ||||
|     void givenCredentials_whenHttpGetWithId_thenReturnUser() throws Exception { | ||||
|         String userId = "1"; | ||||
|         // @formatter:off | ||||
|         when(userService.findById("1")).thenReturn(UserTestUtility.createUserWithId(userId)); | ||||
| 
 | ||||
|         MvcResult result = mockMvc | ||||
|           .perform(get("/api/v1/users/"+userId) | ||||
|             .accept("application/json")) | ||||
|           .andDo(print()) | ||||
|           .andReturn(); | ||||
|         assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); | ||||
|         assertNotNull(result.getResponse()); | ||||
|         assertEquals("jhondoe",objectMapper.readValue(result.getResponse().getContentAsString(),  User.class).getUsername()); | ||||
| 
 | ||||
|         // @formatter:on | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("Test Get All Users") | ||||
|     void givenCredentials_whenHttpGetWithoutId_thenReturnAllUsers() throws Exception { | ||||
|         // @formatter:off | ||||
|         when(userService.findAll()).thenReturn(UserTestUtility.createUsers()); | ||||
| 
 | ||||
|         MvcResult result = mockMvc | ||||
|           .perform(get("/api/v1/users/") | ||||
|             .accept("application/json")) | ||||
|           .andDo(print()) | ||||
|           .andReturn(); | ||||
|         assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); | ||||
|         assertNotNull(result.getResponse()); | ||||
|         assertTrue(result.getResponse().getContentAsString().contains("jane.doe")); | ||||
|         // @formatter:on | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @WithMockUser | ||||
|     @DisplayName("Test Delete a User") | ||||
|     void givenCredentials_whenHttpDelete_thenDeleteUser() throws Exception { | ||||
|         String userId = "1"; | ||||
|         doNothing().when(userService).deleteUser(userId); | ||||
|         // @formatter:off | ||||
|         MvcResult result = mockMvc | ||||
|           .perform(delete("/api/v1/users/"+userId) | ||||
|             .accept("application/json")) | ||||
|           .andDo(print()) | ||||
|           .andReturn(); | ||||
|         assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); | ||||
|         assertNotNull(result.getResponse()); | ||||
|         assertTrue(result.getResponse().getContentAsString().contains("The user has been deleted successfully")); | ||||
|         // @formatter:on | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,92 @@ | ||||
| package com.baeldung.httpfirewall.service; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.dao.InMemoryUserDao; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.model.User; | ||||
| import com.baeldung.httpfirewall.utility.UserTestUtility; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.DisplayName; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.mockito.InjectMocks; | ||||
| import org.mockito.Mock; | ||||
| import org.mockito.MockitoAnnotations; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| 
 | ||||
| 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.mockito.Mockito.doNothing; | ||||
| import static org.mockito.Mockito.times; | ||||
| import static org.mockito.Mockito.verify; | ||||
| import static org.mockito.Mockito.when; | ||||
| 
 | ||||
| @DisplayName("UserService Unit Tests") | ||||
| class UserServiceUnitTest { | ||||
| 
 | ||||
|     @InjectMocks | ||||
|     private UserServiceImpl userService; | ||||
| 
 | ||||
|     @Mock | ||||
|     private InMemoryUserDao userDao; | ||||
| 
 | ||||
|     @BeforeEach | ||||
|     void setup() { | ||||
|         MockitoAnnotations.openMocks(this); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @DisplayName("Check Create User") | ||||
|     void whenCalledCreateUser_thenVerify() { | ||||
|         User user = UserTestUtility.createUser(); | ||||
|         doNothing().when(userDao).save(user); | ||||
| 
 | ||||
|         userService.saveUser(user); | ||||
|         verify(userDao, times(1)).save(user); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     @Test | ||||
|     @DisplayName("Check Get User") | ||||
|     void givenUserId_whenCalledFindById_thenReturnUser() { | ||||
|         User user = UserTestUtility.createUserWithId("1").orElse(new User("1", "jhondoe", "jhon.doe@gmail.com")); | ||||
| 
 | ||||
|         when(userDao.findById(user.getId())).thenReturn(Optional.of(user)); | ||||
| 
 | ||||
|         User actualUser = userService.findById("1").get(); | ||||
| 
 | ||||
|         assertNotNull(actualUser); | ||||
|         assertEquals("jhondoe", actualUser.getUsername()); | ||||
|         verify(userDao, times(1)).findById(user.getId()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @DisplayName("Check Get All Users") | ||||
|     void whenCalledFindAll_thenReturnAllUsers() { | ||||
|         List<User> users = UserTestUtility.createUsers().orElse(new ArrayList<>()); | ||||
| 
 | ||||
|         when(userDao.findAll()).thenReturn(Optional.of(users)); | ||||
| 
 | ||||
|         Optional<List<User>> actualUsers = userService.findAll(); | ||||
| 
 | ||||
|         assertNotNull(actualUsers); | ||||
|         assertEquals(2, users.size()); | ||||
|         verify(userDao, times(1)).findAll(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @DisplayName("Check Delete Users") | ||||
|     void givenId_whenCalledDeleteUser_thenDeleteUser() { | ||||
|         User user = UserTestUtility.createUserWithId("1").orElse(new User()); | ||||
| 
 | ||||
|         doNothing().when(userDao).delete(user.getId()); | ||||
|         userService.deleteUser(user.getId()); | ||||
|         verify(userDao, times(1)).delete(user.getId()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,33 @@ | ||||
| package com.baeldung.httpfirewall.utility; | ||||
| 
 | ||||
| import com.baeldung.httpfirewall.model.User; | ||||
| 
 | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| import java.util.UUID; | ||||
| 
 | ||||
| public class UserTestUtility { | ||||
|     public static User createUser() { | ||||
|         return new User(UUID.randomUUID().toString(),"jhondoe", "jhondoe@gmail.com"); | ||||
|     } | ||||
| 
 | ||||
|     public static User createUserWithoutId() { | ||||
|         return new User("","jhondoe", "jhondoe@gmail.com"); | ||||
|     } | ||||
| 
 | ||||
|     public static Optional<User> createUserWithId(String id) { | ||||
|         // @formatter:off | ||||
|         return Optional.of(new User(id, "jhondoe", "jhon.doe@gmail.com")); | ||||
|         // @formatter:on | ||||
|     } | ||||
| 
 | ||||
|     public static Optional<List<User>> createUsers() { | ||||
|         // @formatter:off | ||||
|         return Optional.of(Arrays.asList( | ||||
|           new User(UUID.randomUUID().toString(), "jhondoe","jhon.doe@gmail.com" ), | ||||
|           new User(UUID.randomUUID().toString(), "janedoe","jane.doe@gmail.com" )) | ||||
|         ); | ||||
|         // @formatter:on | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user