diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredApplication.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredApplication.java new file mode 100644 index 0000000000..0495e0f716 --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.annotations.globalmethod; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +@SpringBootApplication +@EnableWebSecurity +public class AnnotationSecuredApplication { + + public static void main(String[] args) { + SpringApplication.run(AnnotationSecuredApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredController.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredController.java new file mode 100644 index 0000000000..4687299ae5 --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredController.java @@ -0,0 +1,50 @@ +package com.baeldung.annotations.globalmethod; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.security.RolesAllowed; + +@RestController +@EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true) +public class AnnotationSecuredController { + + @Autowired + DifferentClass differentClass; + + @GetMapping("/public") + public String publicHello() { + return "Hello Public"; + } + + @RolesAllowed("ADMIN") + @GetMapping("/admin") + public String adminHello() { + return "Hello Admin"; + } + + @RolesAllowed("USER") + @GetMapping("/protected") + public String jsr250Hello() { + return "Hello Jsr250"; + } + + @GetMapping("/indirect") + public String indirectHello() { + return jsr250Hello(); + } + + @GetMapping("/differentclass") + public String differentClassHello() { + return differentClass.differentJsr250Hello(); + } + + @PreAuthorize("hasRole('USER')") + public String preAuthorizeHello() { + return "Hello PreAuthorize"; + } + +} diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredStaticResourceConfig.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredStaticResourceConfig.java new file mode 100644 index 0000000000..467285adfa --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/AnnotationSecuredStaticResourceConfig.java @@ -0,0 +1,22 @@ +package com.baeldung.annotations.globalmethod; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; + + +@Configuration +@EnableWebSecurity +public class AnnotationSecuredStaticResourceConfig extends WebSecurityConfigurerAdapter { + + @Bean + public WebSecurityCustomizer ignoreResources() { + return (webSecurity) -> webSecurity + .ignoring() + .antMatchers("/hello/*"); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/DifferentClass.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/DifferentClass.java new file mode 100644 index 0000000000..9bcc352d9a --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/globalmethod/DifferentClass.java @@ -0,0 +1,13 @@ +package com.baeldung.annotations.globalmethod; + +import org.springframework.stereotype.Component; + +import javax.annotation.security.RolesAllowed; + +@Component +public class DifferentClass { + @RolesAllowed("USER") + public String differentJsr250Hello() { + return "Hello Jsr250"; + } +} diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/ConfigSecuredApplication.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/ConfigSecuredApplication.java new file mode 100644 index 0000000000..13e405ee22 --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/ConfigSecuredApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.annotations.websecurity; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +@SpringBootApplication +@EnableWebSecurity +public class ConfigSecuredApplication { + + public static void main(String[] args) { + SpringApplication.run(ConfigSecuredApplication.class, args); + } +} diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/ConfigSecuredController.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/ConfigSecuredController.java new file mode 100644 index 0000000000..198efb8353 --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/ConfigSecuredController.java @@ -0,0 +1,30 @@ +package com.baeldung.annotations.websecurity; + +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@RestController +@EnableWebSecurity +public class ConfigSecuredController { + + @GetMapping("/public") + public String publicHello() { + return "Hello Public"; + } + + @GetMapping("/protected") + public String protectedHello() { + return "Hello from protected"; + } + + @GetMapping("/admin") + public String adminHello() { + return "Hello from admin"; + } + +} diff --git a/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/CustomWebSecurityConfig.java b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/CustomWebSecurityConfig.java new file mode 100644 index 0000000000..ce874e313e --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/java/com/baeldung/annotations/websecurity/CustomWebSecurityConfig.java @@ -0,0 +1,29 @@ +package com.baeldung.annotations.websecurity; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@EnableWebSecurity +public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .antMatchers("/admin/**") + .hasRole("ADMIN") + .antMatchers("/protected/**") + .hasRole("USER"); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web + .ignoring() + .antMatchers("/public/*"); + } +} diff --git a/spring-boot-modules/spring-boot-security/src/main/resources/public/hello/baeldung.txt b/spring-boot-modules/spring-boot-security/src/main/resources/public/hello/baeldung.txt new file mode 100644 index 0000000000..b58fe6d244 --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/main/resources/public/hello/baeldung.txt @@ -0,0 +1 @@ +Hello From Baeldung \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/annotations/globalmethod/GlobalMethodSpringBootIntegrationTest.java b/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/annotations/globalmethod/GlobalMethodSpringBootIntegrationTest.java new file mode 100644 index 0000000000..be9dff714b --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/annotations/globalmethod/GlobalMethodSpringBootIntegrationTest.java @@ -0,0 +1,104 @@ +package com.baeldung.annotations.globalmethod; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +public class GlobalMethodSpringBootIntegrationTest { + public static final String HELLO_JSR_250 = "Hello Jsr250"; + public static final String HELLO_PUBLIC = "Hello Public"; + public static final String HELLO_PRE_AUTHORIZE = "Hello PreAuthorize"; + public static final String PUBLIC_RESOURCE = "/hello/baeldung.txt"; + public static final String HELLO_FROM_PUBLIC_RESOURCE = "Hello From Baeldung"; + private static final String PROTECTED_METHOD = "/protected"; + + @Autowired + private TestRestTemplate template; + + @Autowired + private AnnotationSecuredController api; + + @WithMockUser(username="baeldung", roles = "USER") + @Test + public void givenUserWithRole_whenJsr250_thenOk() { + assertThat(api.jsr250Hello()).isEqualTo(HELLO_JSR_250); + } + + @WithMockUser(username="baeldung", roles = "NOT-USER") + @Test(expected = AccessDeniedException.class) + public void givenWrongRole_whenJsr250_thenAccessDenied() { + api.jsr250Hello(); + } + + @Test + @WithAnonymousUser + public void givenAnonymousUser_whenPublic_thenOk() { + assertThat(api.publicHello()).isEqualTo(HELLO_PUBLIC); + } + + @Test(expected = AccessDeniedException.class) + @WithAnonymousUser + public void givenAnonymousUser_whenJsr250_thenAccessDenied() { + api.jsr250Hello(); + } + + // Tests for indirect calling of method + @Test + @WithAnonymousUser + public void givenAnonymousUser_whenIndirectCall_thenNoSecurity() { + assertThat(api.indirectHello()).isEqualTo(HELLO_JSR_250); + } + + @Test(expected = AccessDeniedException.class) + @WithAnonymousUser + public void givenAnonymousUser_whenIndirectToDifferentClass_thenAccessDenied() { + api.differentClassHello(); + } + + // Tests for static resource + @Test + public void givenPublicResource_whenGetViaWeb_thenOk() { + ResponseEntity result = template.getForEntity(PUBLIC_RESOURCE, String.class); + assertEquals(HELLO_FROM_PUBLIC_RESOURCE, result.getBody()); + } + + @Test + public void givenProtectedMethod_whenGetViaWeb_thenRedirectToLogin() { + ResponseEntity result = template.getForEntity(PROTECTED_METHOD, String.class); + assertEquals(HttpStatus.FOUND, result.getStatusCode()); + } + + // Tests for preAuthorize annotations + @WithMockUser(username="baeldung", roles = "USER") + @Test + public void givenUserWithRole_whenCallPreAuthorize_thenOk() { + assertThat(api.preAuthorizeHello()).isEqualTo(HELLO_PRE_AUTHORIZE); + } + + @WithMockUser(username="baeldung", roles = "NOT-USER") + @Test(expected = AccessDeniedException.class) + public void givenWrongRole_whenCallPreAuthorize_thenAccessDenied() { + api.preAuthorizeHello(); + } + + @Test(expected = AccessDeniedException.class) + @WithAnonymousUser + public void givenAnonymousUser_whenCallPreAuthorize_thenAccessDenied() { + api.preAuthorizeHello(); + } + +} diff --git a/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/annotations/websecurity/WebSecuritySpringBootIntegrationTest.java b/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/annotations/websecurity/WebSecuritySpringBootIntegrationTest.java new file mode 100644 index 0000000000..1360ae939d --- /dev/null +++ b/spring-boot-modules/spring-boot-security/src/test/java/com/baeldung/annotations/websecurity/WebSecuritySpringBootIntegrationTest.java @@ -0,0 +1,62 @@ +package com.baeldung.annotations.websecurity; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT) +public class WebSecuritySpringBootIntegrationTest { + private static final String PUBLIC_RESOURCE = "/hello/baeldung.txt"; + private static final String HELLO_FROM_PUBLIC_RESOURCE = "Hello From Baeldung"; + + @Autowired + private ConfigSecuredController api; + + @Autowired + private TestRestTemplate template; + + @Test + public void whenCallPublicDirectly_thenOk() { + assertThat(api.publicHello()).isEqualTo("Hello Public"); + } + + @Test + public void whenCallProtectedDirectly_thenNoSecurity() { + assertThat(api.protectedHello()).isEqualTo("Hello from protected"); + } + + @Test + public void whenGetProtectedViaWeb_thenForbidden() { + ResponseEntity result = template.getForEntity("/protected", String.class); + assertEquals(HttpStatus.FORBIDDEN, result.getStatusCode()); + } + + @Test + public void whenGetAdminViaWeb_thenForbidden() { + ResponseEntity result = template.getForEntity("/admin", String.class); + assertEquals(HttpStatus.FORBIDDEN, result.getStatusCode()); + } + + @Test + public void whenGetPublicViaWeb_thenSuccess() { + ResponseEntity result = template.getForEntity("/public", String.class); + assertEquals(HttpStatus.OK, result.getStatusCode()); + } + + @Test + public void givenPublicResource_whenGetViaWeb_thenOk() { + ResponseEntity result = template.getForEntity(PUBLIC_RESOURCE, String.class); + assertEquals(HELLO_FROM_PUBLIC_RESOURCE, result.getBody()); + } + +}