From 97f67354992beae9f6eac8dfcd057c0ea3dea6fa Mon Sep 17 00:00:00 2001 From: timis1 <12120641+timis1@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:22:12 +0200 Subject: [PATCH] JAVA-29289 Upgrade spring-security-core (#15838) Co-authored-by: timis1 --- ...temptedPathAuthorizationAuditListener.java | 6 ++-- .../app/config/WebSecurityConfig.java | 9 ++--- .../app/controller/TaskController.java | 7 ++-- .../com/baeldung/app/filter/CustomFilter.java | 2 +- ...onAllowedMethodSecurityMetadataSource.java | 35 +++++++------------ .../DenyMethodSecurityConfig.java | 23 +++++++----- .../filterresponse/config/AppConfig.java | 3 +- .../baeldung/filterresponse/model/Item.java | 6 ++-- ...enyOnMissingControllerIntegrationTest.java | 6 ++-- ...SpringSecurityJsonViewIntegrationTest.java | 4 +-- .../MethodSecurityIntegrationTest.java | 7 ++-- 11 files changed, 54 insertions(+), 54 deletions(-) diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/auditing/ExposeAttemptedPathAuthorizationAuditListener.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/auditing/ExposeAttemptedPathAuthorizationAuditListener.java index ff53b3cc6a..0f966709b9 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/auditing/ExposeAttemptedPathAuthorizationAuditListener.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/auditing/ExposeAttemptedPathAuthorizationAuditListener.java @@ -19,13 +19,13 @@ public class ExposeAttemptedPathAuthorizationAuditListener extends AbstractAutho @Override public void onApplicationEvent(AuthorizationEvent event) { if (event instanceof AuthorizationDeniedEvent) { - onAuthorizationFailureEvent((AuthorizationDeniedEvent) event); + onAuthorizationFailureEvent(event); } } - private void onAuthorizationFailureEvent(AuthorizationDeniedEvent event) { + private void onAuthorizationFailureEvent(AuthorizationEvent event) { String name = this.getName(event.getAuthentication()); - Map data = new LinkedHashMap(); + Map data = new LinkedHashMap<>(); Object details = this.getDetails(event.getAuthentication()); if (details != null) { data.put("details", details); diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/config/WebSecurityConfig.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/config/WebSecurityConfig.java index 24f7dc8a5b..dc6f636715 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/config/WebSecurityConfig.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/config/WebSecurityConfig.java @@ -3,9 +3,10 @@ package com.baeldung.app.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; 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.configurers.AbstractHttpConfigurer; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; @@ -14,7 +15,7 @@ import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) +@EnableMethodSecurity public class WebSecurityConfig { @Bean @@ -25,8 +26,8 @@ public class WebSecurityConfig { .anyRequest() .authenticated()) .httpBasic(Customizer.withDefaults()) - .logout(logout -> logout.disable()) - .csrf(csrf -> csrf.disable()); + .logout(AbstractHttpConfigurer::disable) + .csrf(AbstractHttpConfigurer::disable); return http.build(); } diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java index f2d479d782..217719cba6 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java @@ -6,9 +6,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +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.RequestMethod; @Controller @RequestMapping("api/tasks") @@ -20,14 +21,14 @@ public class TaskController { @Autowired(required = false) private UserDetailsService userDetailsService; - @RequestMapping(method = RequestMethod.GET) + @GetMapping public ResponseEntity> findAllTasks() { Iterable tasks = taskService.findAll(); return ResponseEntity.ok().body(tasks); } - @RequestMapping(method = RequestMethod.POST, consumes = "application/json") + @PostMapping(consumes = "application/json") public ResponseEntity> addTasks(@RequestBody Iterable newTasks) { Iterable tasks = taskService.save(newTasks); diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/filter/CustomFilter.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/filter/CustomFilter.java index c16202976b..8b47cf3f17 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/filter/CustomFilter.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/filter/CustomFilter.java @@ -14,7 +14,7 @@ public class CustomFilter implements Filter { private static Logger LOGGER = LoggerFactory.getLogger(CustomFilter.class); @Override - public void init(FilterConfig config) throws ServletException { + public void init(FilterConfig config) { } @Override diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/denyonmissing/CustomPermissionAllowedMethodSecurityMetadataSource.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/denyonmissing/CustomPermissionAllowedMethodSecurityMetadataSource.java index c6508f0ab3..631987ba4d 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/denyonmissing/CustomPermissionAllowedMethodSecurityMetadataSource.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/denyonmissing/CustomPermissionAllowedMethodSecurityMetadataSource.java @@ -2,34 +2,31 @@ package com.baeldung.denyonmissing; import static org.springframework.security.access.annotation.Jsr250SecurityConfig.DENY_ALL_ATTRIBUTE; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.function.Supplier; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.core.annotation.MergedAnnotation; +import org.aopalliance.intercept.MethodInvocation; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.security.access.ConfigAttribute; -import org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; -public class CustomPermissionAllowedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource { - @Override - protected Collection findAttributes(Class clazz) { - return null; - } +@Component +public class CustomPermissionAllowedMethodSecurityMetadataSource implements AuthorizationManager { @Override - protected Collection findAttributes(Method method, Class targetClass) { - MergedAnnotations annotations = MergedAnnotations.from(method, - MergedAnnotations.SearchStrategy.DIRECT); + public AuthorizationDecision check(Supplier authentication, MethodInvocation mi) { + MergedAnnotations annotations = MergedAnnotations.from(mi.getMethod(), MergedAnnotations.SearchStrategy.DIRECT); List attributes = new ArrayList<>(); - MergedAnnotations classAnnotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.DIRECT); + MergedAnnotations classAnnotations = MergedAnnotations.from(DenyOnMissingController.class, MergedAnnotations.SearchStrategy.DIRECT); // if the class is annotated as @Controller we should by default deny access to every method if (classAnnotations.get(Controller.class).isPresent()) { attributes.add(DENY_ALL_ATTRIBUTE); @@ -38,12 +35,6 @@ public class CustomPermissionAllowedMethodSecurityMetadataSource extends Abstrac if (annotations.get(PreAuthorize.class).isPresent() || annotations.get(PostAuthorize.class).isPresent()) { return null; } - - return attributes; - } - - @Override - public Collection getAllConfigAttributes() { - return null; + return new AuthorizationDecision(!Collections.disjoint(attributes, authentication.get().getAuthorities())); } } \ No newline at end of file diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/denyonmissing/DenyMethodSecurityConfig.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/denyonmissing/DenyMethodSecurityConfig.java index 695f81eb54..03fe2b6887 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/denyonmissing/DenyMethodSecurityConfig.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/denyonmissing/DenyMethodSecurityConfig.java @@ -1,10 +1,12 @@ package com.baeldung.denyonmissing; +import org.springframework.aop.Advisor; +import org.springframework.aop.support.JdkRegexpMethodPointcut; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.access.method.MethodSecurityMetadataSource; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; +import org.springframework.security.authorization.method.AuthorizationInterceptorsOrder; +import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; @@ -12,11 +14,16 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager; @Configuration @EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class DenyMethodSecurityConfig extends GlobalMethodSecurityConfiguration { - @Override - protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() { - return new CustomPermissionAllowedMethodSecurityMetadataSource(); +@EnableMethodSecurity +public class DenyMethodSecurityConfig { + + @Bean + public Advisor preAuthorize(CustomPermissionAllowedMethodSecurityMetadataSource manager) { + JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut(); + pattern.setPattern("com.baeldung.denyonmissing.*"); + AuthorizationManagerBeforeMethodInterceptor interceptor = new AuthorizationManagerBeforeMethodInterceptor(pattern, manager); + interceptor.setOrder(AuthorizationInterceptorsOrder.PRE_AUTHORIZE.getOrder() - 1); + return interceptor; } @Bean diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/filterresponse/config/AppConfig.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/filterresponse/config/AppConfig.java index d57c1f2e5f..4f66c63817 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/filterresponse/config/AppConfig.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/filterresponse/config/AppConfig.java @@ -6,6 +6,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; 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.configurers.AbstractHttpConfigurer; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -42,7 +43,7 @@ public class AppConfig implements WebMvcConfigurer { .anyRequest() .authenticated()) .httpBasic(Customizer.withDefaults()) - .csrf(csrf -> csrf.disable()); + .csrf(AbstractHttpConfigurer::disable); return http.build(); } diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/filterresponse/model/Item.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/filterresponse/model/Item.java index 9ebdc6bad0..9cc35d3829 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/filterresponse/model/Item.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/filterresponse/model/Item.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.annotation.JsonView; public class Item { @JsonView(View.User.class) - private int id; + private final int id; @JsonView(View.User.class) - private String name; + private final String name; @JsonView(View.Admin.class) - private String ownerName; + private final String ownerName; public Item(int id, String name, String ownerName) { this.id = id; diff --git a/spring-security-modules/spring-security-core/src/test/java/com/baeldung/denyonmissing/DenyOnMissingControllerIntegrationTest.java b/spring-security-modules/spring-security-core/src/test/java/com/baeldung/denyonmissing/DenyOnMissingControllerIntegrationTest.java index 2f67168229..a6a9653013 100644 --- a/spring-security-modules/spring-security-core/src/test/java/com/baeldung/denyonmissing/DenyOnMissingControllerIntegrationTest.java +++ b/spring-security-modules/spring-security-core/src/test/java/com/baeldung/denyonmissing/DenyOnMissingControllerIntegrationTest.java @@ -41,10 +41,8 @@ public class DenyOnMissingControllerIntegrationTest { @Test @WithMockUser(username = "user") - public void givenANormalUser_whenCallingBye_thenAccessDenied() throws Exception { - ServletException exception = Assertions.assertThrows(ServletException.class, () -> { - mockMvc.perform(get("/bye")); - }); + public void givenANormalUser_whenCallingBye_thenAccessDenied() { + ServletException exception = Assertions.assertThrows(ServletException.class, () -> mockMvc.perform(get("/bye"))); Assertions.assertNotNull(exception); Assertions.assertEquals(exception.getCause().getClass(), AccessDeniedException.class); diff --git a/spring-security-modules/spring-security-core/src/test/java/com/baeldung/filterresponse/SpringSecurityJsonViewIntegrationTest.java b/spring-security-modules/spring-security-core/src/test/java/com/baeldung/filterresponse/SpringSecurityJsonViewIntegrationTest.java index fd80ae48c9..de4afa4132 100644 --- a/spring-security-modules/spring-security-core/src/test/java/com/baeldung/filterresponse/SpringSecurityJsonViewIntegrationTest.java +++ b/spring-security-modules/spring-security-core/src/test/java/com/baeldung/filterresponse/SpringSecurityJsonViewIntegrationTest.java @@ -15,7 +15,7 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -66,6 +66,6 @@ public class SpringSecurityJsonViewIntegrationTest { }); Assertions.assertEquals(exception.getCause().getClass(), IllegalArgumentException.class); - assertTrue(exception.getCause().getMessage().equals("Ambiguous @JsonView declaration for roles ROLE_ADMIN,ROLE_USER")); + assertEquals("Ambiguous @JsonView declaration for roles ROLE_ADMIN,ROLE_USER", exception.getCause().getMessage()); } } diff --git a/spring-security-modules/spring-security-core/src/test/java/com/baeldung/methodsecurity/MethodSecurityIntegrationTest.java b/spring-security-modules/spring-security-core/src/test/java/com/baeldung/methodsecurity/MethodSecurityIntegrationTest.java index 0ad01d9954..6f9fac5bb4 100644 --- a/spring-security-modules/spring-security-core/src/test/java/com/baeldung/methodsecurity/MethodSecurityIntegrationTest.java +++ b/spring-security-modules/spring-security-core/src/test/java/com/baeldung/methodsecurity/MethodSecurityIntegrationTest.java @@ -1,6 +1,7 @@ package com.baeldung.methodsecurity; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.ArrayList; @@ -50,7 +51,7 @@ public class MethodSecurityIntegrationTest { @WithMockUser(username = "john", roles = { "EDITOR" }) public void givenUsernameJohn_whenCallIsValidUsername_thenReturnTrue() { boolean isValid = userRoleService.isValidUsername("john"); - assertEquals(true, isValid); + assertTrue(isValid); } @Test(expected = AccessDeniedException.class) @@ -60,7 +61,7 @@ public class MethodSecurityIntegrationTest { } @Test(expected = AccessDeniedException.class) - @WithMockUser(username = "john", roles = { "USER" }) + @WithMockUser(username = "john") public void givenRoleUser_whenCallGetUsername2_thenReturnAccessDenied() { userRoleService.getUsername2(); } @@ -76,7 +77,7 @@ public class MethodSecurityIntegrationTest { @WithMockUser(username = "john", roles = { "VIEWER" }) public void givenUsernameJerry_whenCallIsValidUsername2_thenReturnFalse() { boolean isValid = userRoleService.isValidUsername2("jerry"); - assertEquals(false, isValid); + assertFalse(isValid); } @Test