JAVA-29289 Upgrade spring-security-core (#15838)

Co-authored-by: timis1 <noreplay@yahoo.com>
This commit is contained in:
timis1 2024-02-11 23:22:12 +02:00 committed by GitHub
parent 3dd8fc58fa
commit 97f6735499
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 54 additions and 54 deletions

View File

@ -19,13 +19,13 @@ public class ExposeAttemptedPathAuthorizationAuditListener extends AbstractAutho
@Override @Override
public void onApplicationEvent(AuthorizationEvent event) { public void onApplicationEvent(AuthorizationEvent event) {
if (event instanceof AuthorizationDeniedEvent) { 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()); String name = this.getName(event.getAuthentication());
Map<String, Object> data = new LinkedHashMap(); Map<String, Object> data = new LinkedHashMap<>();
Object details = this.getDetails(event.getAuthentication()); Object details = this.getDetails(event.getAuthentication());
if (details != null) { if (details != null) {
data.put("details", details); data.put("details", details);

View File

@ -3,9 +3,10 @@ package com.baeldung.app.config;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer; 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.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 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.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@ -14,7 +15,7 @@ import org.springframework.security.web.SecurityFilterChain;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity
public class WebSecurityConfig { public class WebSecurityConfig {
@Bean @Bean
@ -25,8 +26,8 @@ public class WebSecurityConfig {
.anyRequest() .anyRequest()
.authenticated()) .authenticated())
.httpBasic(Customizer.withDefaults()) .httpBasic(Customizer.withDefaults())
.logout(logout -> logout.disable()) .logout(AbstractHttpConfigurer::disable)
.csrf(csrf -> csrf.disable()); .csrf(AbstractHttpConfigurer::disable);
return http.build(); return http.build();
} }

View File

@ -6,9 +6,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Controller; 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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller @Controller
@RequestMapping("api/tasks") @RequestMapping("api/tasks")
@ -20,14 +21,14 @@ public class TaskController {
@Autowired(required = false) @Autowired(required = false)
private UserDetailsService userDetailsService; private UserDetailsService userDetailsService;
@RequestMapping(method = RequestMethod.GET) @GetMapping
public ResponseEntity<Iterable<Task>> findAllTasks() { public ResponseEntity<Iterable<Task>> findAllTasks() {
Iterable<Task> tasks = taskService.findAll(); Iterable<Task> tasks = taskService.findAll();
return ResponseEntity.ok().body(tasks); return ResponseEntity.ok().body(tasks);
} }
@RequestMapping(method = RequestMethod.POST, consumes = "application/json") @PostMapping(consumes = "application/json")
public ResponseEntity<Iterable<Task>> addTasks(@RequestBody Iterable<Task> newTasks) { public ResponseEntity<Iterable<Task>> addTasks(@RequestBody Iterable<Task> newTasks) {
Iterable<Task> tasks = taskService.save(newTasks); Iterable<Task> tasks = taskService.save(newTasks);

View File

@ -14,7 +14,7 @@ public class CustomFilter implements Filter {
private static Logger LOGGER = LoggerFactory.getLogger(CustomFilter.class); private static Logger LOGGER = LoggerFactory.getLogger(CustomFilter.class);
@Override @Override
public void init(FilterConfig config) throws ServletException { public void init(FilterConfig config) {
} }
@Override @Override

View File

@ -2,34 +2,31 @@ package com.baeldung.denyonmissing;
import static org.springframework.security.access.annotation.Jsr250SecurityConfig.DENY_ALL_ATTRIBUTE; 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.ArrayList;
import java.util.Collection; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import org.springframework.core.annotation.AnnotationUtils; import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.security.access.ConfigAttribute; 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.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize; 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; import org.springframework.stereotype.Controller;
public class CustomPermissionAllowedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource { @Component
@Override public class CustomPermissionAllowedMethodSecurityMetadataSource implements AuthorizationManager<MethodInvocation> {
protected Collection<ConfigAttribute> findAttributes(Class<?> clazz) {
return null;
}
@Override @Override
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) { public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
MergedAnnotations annotations = MergedAnnotations.from(method, MergedAnnotations annotations = MergedAnnotations.from(mi.getMethod(), MergedAnnotations.SearchStrategy.DIRECT);
MergedAnnotations.SearchStrategy.DIRECT);
List<ConfigAttribute> attributes = new ArrayList<>(); List<ConfigAttribute> 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 the class is annotated as @Controller we should by default deny access to every method
if (classAnnotations.get(Controller.class).isPresent()) { if (classAnnotations.get(Controller.class).isPresent()) {
attributes.add(DENY_ALL_ATTRIBUTE); 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()) { if (annotations.get(PreAuthorize.class).isPresent() || annotations.get(PostAuthorize.class).isPresent()) {
return null; return null;
} }
return new AuthorizationDecision(!Collections.disjoint(attributes, authentication.get().getAuthorities()));
return attributes;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
} }
} }

View File

@ -1,10 +1,12 @@
package com.baeldung.denyonmissing; 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.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.method.MethodSecurityMetadataSource; import org.springframework.security.authorization.method.AuthorizationInterceptorsOrder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
@ -12,11 +14,16 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity
public class DenyMethodSecurityConfig extends GlobalMethodSecurityConfiguration { public class DenyMethodSecurityConfig {
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() { @Bean
return new CustomPermissionAllowedMethodSecurityMetadataSource(); 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 @Bean

View File

@ -6,6 +6,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer; import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@ -42,7 +43,7 @@ public class AppConfig implements WebMvcConfigurer {
.anyRequest() .anyRequest()
.authenticated()) .authenticated())
.httpBasic(Customizer.withDefaults()) .httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable()); .csrf(AbstractHttpConfigurer::disable);
return http.build(); return http.build();
} }

View File

@ -6,11 +6,11 @@ import com.fasterxml.jackson.annotation.JsonView;
public class Item { public class Item {
@JsonView(View.User.class) @JsonView(View.User.class)
private int id; private final int id;
@JsonView(View.User.class) @JsonView(View.User.class)
private String name; private final String name;
@JsonView(View.Admin.class) @JsonView(View.Admin.class)
private String ownerName; private final String ownerName;
public Item(int id, String name, String ownerName) { public Item(int id, String name, String ownerName) {
this.id = id; this.id = id;

View File

@ -41,10 +41,8 @@ public class DenyOnMissingControllerIntegrationTest {
@Test @Test
@WithMockUser(username = "user") @WithMockUser(username = "user")
public void givenANormalUser_whenCallingBye_thenAccessDenied() throws Exception { public void givenANormalUser_whenCallingBye_thenAccessDenied() {
ServletException exception = Assertions.assertThrows(ServletException.class, () -> { ServletException exception = Assertions.assertThrows(ServletException.class, () -> mockMvc.perform(get("/bye")));
mockMvc.perform(get("/bye"));
});
Assertions.assertNotNull(exception); Assertions.assertNotNull(exception);
Assertions.assertEquals(exception.getCause().getClass(), AccessDeniedException.class); Assertions.assertEquals(exception.getCause().getClass(), AccessDeniedException.class);

View File

@ -15,7 +15,7 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; 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.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -66,6 +66,6 @@ public class SpringSecurityJsonViewIntegrationTest {
}); });
Assertions.assertEquals(exception.getCause().getClass(), IllegalArgumentException.class); 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());
} }
} }

View File

@ -1,6 +1,7 @@
package com.baeldung.methodsecurity; package com.baeldung.methodsecurity;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.ArrayList; import java.util.ArrayList;
@ -50,7 +51,7 @@ public class MethodSecurityIntegrationTest {
@WithMockUser(username = "john", roles = { "EDITOR" }) @WithMockUser(username = "john", roles = { "EDITOR" })
public void givenUsernameJohn_whenCallIsValidUsername_thenReturnTrue() { public void givenUsernameJohn_whenCallIsValidUsername_thenReturnTrue() {
boolean isValid = userRoleService.isValidUsername("john"); boolean isValid = userRoleService.isValidUsername("john");
assertEquals(true, isValid); assertTrue(isValid);
} }
@Test(expected = AccessDeniedException.class) @Test(expected = AccessDeniedException.class)
@ -60,7 +61,7 @@ public class MethodSecurityIntegrationTest {
} }
@Test(expected = AccessDeniedException.class) @Test(expected = AccessDeniedException.class)
@WithMockUser(username = "john", roles = { "USER" }) @WithMockUser(username = "john")
public void givenRoleUser_whenCallGetUsername2_thenReturnAccessDenied() { public void givenRoleUser_whenCallGetUsername2_thenReturnAccessDenied() {
userRoleService.getUsername2(); userRoleService.getUsername2();
} }
@ -76,7 +77,7 @@ public class MethodSecurityIntegrationTest {
@WithMockUser(username = "john", roles = { "VIEWER" }) @WithMockUser(username = "john", roles = { "VIEWER" })
public void givenUsernameJerry_whenCallIsValidUsername2_thenReturnFalse() { public void givenUsernameJerry_whenCallIsValidUsername2_thenReturnFalse() {
boolean isValid = userRoleService.isValidUsername2("jerry"); boolean isValid = userRoleService.isValidUsername2("jerry");
assertEquals(false, isValid); assertFalse(isValid);
} }
@Test @Test