diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java new file mode 100644 index 0000000000..150fe399d1 --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/SecuredEcommerceApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.permitallanonymous; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan("com.baeldung.permitallanonymous.*") +public class SecuredEcommerceApplication { + public static void main(String[] args) { + SpringApplication.run(SecuredEcommerceApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java new file mode 100644 index 0000000000..bbfb5b9056 --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/controller/EcommerceController.java @@ -0,0 +1,27 @@ +package com.baeldung.permitallanonymous.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class EcommerceController { + + //can be accessed by only logged-in users + @GetMapping("/private/showCart") + public @ResponseBody String showCart() { + return "Show Cart"; + } + + //can we accessed by both anonymous and authenticated users + @GetMapping("/public/showProducts") + public @ResponseBody String listProducts() { + return "List Products"; + } + + //can be access by only anonymous users not by authenticated users + @GetMapping("/public/registerUser") + public @ResponseBody String registerUser() { + return "Register User"; + } +} diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java new file mode 100644 index 0000000000..68c90fdae0 --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/permitallanonymous/security/EcommerceWebSecurityConfig.java @@ -0,0 +1,41 @@ +package com.baeldung.permitallanonymous.security; + +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.EnableWebSecurity; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +public class EcommerceWebSecurityConfig { + @Bean + public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) { + UserDetails user = User.withUsername("spring") + .password(passwordEncoder.encode("secret")) + .roles("USER") + .build(); + + return new InMemoryUserDetailsManager(user); + } + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/private/**").authenticated().and().httpBasic() + .and().authorizeRequests() + .antMatchers("/public/showProducts").permitAll() + .antMatchers("/public/registerUser").anonymous(); + + return http.build(); + } + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java b/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java new file mode 100644 index 0000000000..3c73caf1fd --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/permitallanonymous/SecureEcommerceApplicationUnitTest.java @@ -0,0 +1,70 @@ +package com.baeldung.permitallanonymous; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SecuredEcommerceApplication.class) +@AutoConfigureMockMvc +public class SecureEcommerceApplicationUnitTest { + @Autowired + private MockMvc mockMvc; + private static final Logger logger = LoggerFactory.getLogger(SecureEcommerceApplicationUnitTest.class); + + @WithAnonymousUser + @Test + public void givenAnonymousUser_whenAccessToUserRegisterPage_thenAllowAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/registerUser")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("Register User")); + } + + @WithMockUser(username = "spring", password = "secret") + @Test + public void givenAuthenticatedUser_whenAccessToUserRegisterPage_thenDenyAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/registerUser")) + .andExpect(MockMvcResultMatchers.status().isForbidden()); + } + + @WithMockUser(username = "spring", password = "secret") + @Test + public void givenAuthenticatedUser_whenAccessToProductLinePage_thenAllowAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/showProducts")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("List Products")); + } + + @WithAnonymousUser + @Test + public void givenAnonymousUser_whenAccessToProductLinePage_thenAllowAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/showProducts")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("List Products")); + } + + @WithMockUser(username = "spring", password = "secret") + @Test + public void givenAuthenticatedUser_whenAccessToCartPage_thenAllowAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/private/showCart")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("Show Cart")); + } + + @WithAnonymousUser + @Test + public void givenAnonymousUser_whenAccessToCartPage_thenDenyAccess() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/private/showCart")) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } +}