JAVA-29289 Upgrade spring-security-core (#15838)
Co-authored-by: timis1 <noreplay@yahoo.com>
This commit is contained in:
parent
3dd8fc58fa
commit
97f6735499
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user