diff --git a/spring-security-modules/spring-security-web-boot-3/pom.xml b/spring-security-modules/spring-security-web-boot-3/pom.xml
index 1fff259c16..9d09d60611 100644
--- a/spring-security-modules/spring-security-web-boot-3/pom.xml
+++ b/spring-security-modules/spring-security-web-boot-3/pom.xml
@@ -1,7 +1,7 @@
+ 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">
4.0.0
spring-security-web-boot-3
0.0.1-SNAPSHOT
@@ -25,6 +25,20 @@
org.springframework.boot
spring-boot-starter-web
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java
new file mode 100644
index 0000000000..e7d6d823a6
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java
@@ -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);
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java
new file mode 100644
index 0000000000..3147b962a3
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java
@@ -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
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java
new file mode 100644
index 0000000000..9bed81bb8f
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java
@@ -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 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 getAllUsers() {
+ return userServiceImpl.findAll().orElse(new ArrayList<>());
+ }
+
+ @DeleteMapping("/{userId}")
+ public ResponseEntity deleteUser(@PathVariable("userId") String userId) {
+ userServiceImpl.deleteUser(userId);
+ return ResponseEntity.ok(new Response(200, "The user has been deleted successfully", System.currentTimeMillis()));
+ }
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java
new file mode 100644
index 0000000000..fb89abf17d
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java
@@ -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 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 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> 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);
+ }
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java
new file mode 100644
index 0000000000..ba1c8d5dea
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java
@@ -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;
+ }
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java
new file mode 100644
index 0000000000..5807a990e7
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java
@@ -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;
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java
new file mode 100644
index 0000000000..d3d3f20f3d
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java
@@ -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 findById(String userId) {
+ return inMemoryUserDao.findById(userId);
+ }
+
+ /**
+ * Fetch all the users in the store
+ * @return A list of all the users
+ */
+ public Optional> 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);
+ }
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties b/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties
new file mode 100644
index 0000000000..cb7e159bf3
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties
@@ -0,0 +1,2 @@
+spring.security.user.name=user
+spring.security.user.password=password
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java
new file mode 100644
index 0000000000..4b4a9a40ce
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java
@@ -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 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());
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java
new file mode 100644
index 0000000000..4f6217ade2
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java
@@ -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
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java
new file mode 100644
index 0000000000..4a58312c0f
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java
@@ -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 users = UserTestUtility.createUsers().orElse(new ArrayList<>());
+
+ when(userDao.findAll()).thenReturn(Optional.of(users));
+
+ Optional> 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());
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java
new file mode 100644
index 0000000000..77953a5176
--- /dev/null
+++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java
@@ -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 createUserWithId(String id) {
+ // @formatter:off
+ return Optional.of(new User(id, "jhondoe", "jhon.doe@gmail.com"));
+ // @formatter:on
+ }
+
+ public static Optional> 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
+ }
+}