[JAVA-29171] Upgrade spring-security-core module to Spring Boot 3 (#15487)

This commit is contained in:
Amit Pandey 2024-01-05 13:40:00 +05:30 committed by GitHub
parent 67c4875aff
commit ff11a92e8a
13 changed files with 106 additions and 123 deletions

View File

@ -10,8 +10,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>spring-security-modules</artifactId>
<artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath>
</parent>
<dependencies>
@ -66,6 +67,10 @@
</plugins>
</build>
<properties>
<start-class>com.baeldung.app.App</start-class>
</properties>
<profiles>
<profile>
<id>live</id>

View File

@ -1,13 +1,10 @@
package com.baeldung.app;
import javax.servlet.Filter;
import jakarta.servlet.Filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
@ -20,7 +17,7 @@ public class App extends SpringBootServletInitializer {
public static class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected javax.servlet.Filter[] getServletFilters() {
protected Filter[] getServletFilters() {
DelegatingFilterProxy delegateFilterProxy = new DelegatingFilterProxy();
delegateFilterProxy.setTargetBeanName("loggingFilter");
return new Filter[] { delegateFilterProxy };

View File

@ -2,13 +2,14 @@ package com.baeldung.app.auditing;
import org.springframework.boot.actuate.audit.AuditEvent;
import org.springframework.boot.actuate.security.AbstractAuthorizationAuditListener;
import org.springframework.security.access.event.AbstractAuthorizationEvent;
import org.springframework.security.access.event.AuthorizationFailureEvent;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationEvent;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
@Component
public class ExposeAttemptedPathAuthorizationAuditListener extends AbstractAuthorizationAuditListener {
@ -16,21 +17,37 @@ public class ExposeAttemptedPathAuthorizationAuditListener extends AbstractAutho
public static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE";
@Override
public void onApplicationEvent(AbstractAuthorizationEvent event) {
if (event instanceof AuthorizationFailureEvent) {
onAuthorizationFailureEvent((AuthorizationFailureEvent) event);
public void onApplicationEvent(AuthorizationEvent event) {
if (event instanceof AuthorizationDeniedEvent) {
onAuthorizationFailureEvent((AuthorizationDeniedEvent) event);
}
}
private void onAuthorizationFailureEvent(AuthorizationFailureEvent event) {
Map<String, Object> data = new HashMap<>();
data.put("type", event.getAccessDeniedException().getClass().getName());
data.put("message", event.getAccessDeniedException().getMessage());
data.put("requestUrl", ((FilterInvocation)event.getSource()).getRequestUrl() );
if (event.getAuthentication().getDetails() != null) {
data.put("details", event.getAuthentication().getDetails());
private void onAuthorizationFailureEvent(AuthorizationDeniedEvent event) {
String name = this.getName(event.getAuthentication());
Map<String, Object> data = new LinkedHashMap();
Object details = this.getDetails(event.getAuthentication());
if (details != null) {
data.put("details", details);
}
publish(new AuditEvent(event.getAuthentication().getName(), AUTHORIZATION_FAILURE,
data));
publish(new AuditEvent(name, "AUTHORIZATION_FAILURE", data));
}
private String getName(Supplier<Authentication> authentication) {
try {
return authentication.get().getName();
} catch (Exception var3) {
return "<unknown>";
}
}
private Object getDetails(Supplier<Authentication> authentication) {
try {
return (authentication.get()).getDetails();
} catch (Exception var3) {
return null;
}
}
}

View File

@ -2,6 +2,7 @@ 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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@ -18,18 +19,14 @@ public class WebSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**", "/js/**", "/loggedout")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.and()
.logout()
.disable()
.csrf()
.disable();
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/css/**", "/js/**", "/loggedout")
.permitAll()
.anyRequest()
.authenticated())
.httpBasic(Customizer.withDefaults())
.logout(logout -> logout.disable())
.csrf(csrf -> csrf.disable());
return http.build();
}

View File

@ -1,23 +1,14 @@
package com.baeldung.app.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.baeldung.app.entity.Task;
import com.baeldung.app.service.TaskService;
import javax.servlet.http.HttpServletRequest;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("api/tasks")

View File

@ -1,8 +1,8 @@
package com.baeldung.app.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class Task {

View File

@ -1,19 +1,13 @@
package com.baeldung.app.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component("loggingFilter")
public class CustomFilter implements Filter {
@ -24,7 +18,7 @@ public class CustomFilter implements Filter {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
LOGGER.info("Request Info : " + req);

View File

@ -1,5 +1,6 @@
package com.baeldung.checkrolejava;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
@ -10,7 +11,6 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import javax.servlet.http.HttpServletRequest;
@Controller
public class UserController {

View File

@ -9,6 +9,8 @@ import java.util.Collection;
import java.util.List;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
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;
@ -23,22 +25,20 @@ public class CustomPermissionAllowedMethodSecurityMetadataSource extends Abstrac
@Override
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
MergedAnnotations annotations = MergedAnnotations.from(method,
MergedAnnotations.SearchStrategy.DIRECT);
List<ConfigAttribute> attributes = new ArrayList<>();
MergedAnnotations classAnnotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.DIRECT);
// if the class is annotated as @Controller we should by default deny access to every method
if (AnnotationUtils.findAnnotation(targetClass, Controller.class) != null) {
if (classAnnotations.get(Controller.class).isPresent()) {
attributes.add(DENY_ALL_ATTRIBUTE);
}
if (annotations != null) {
for (Annotation a : annotations) {
// but not if the method has at least a PreAuthorize or PostAuthorize annotation
if (a instanceof PreAuthorize || a instanceof PostAuthorize) {
return null;
}
}
if (annotations.get(PreAuthorize.class).isPresent() || annotations.get(PostAuthorize.class).isPresent()) {
return null;
}
return attributes;
}

View File

@ -3,6 +3,7 @@ package com.baeldung.filterresponse.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
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.core.userdetails.User;
@ -37,13 +38,11 @@ public class AppConfig implements WebMvcConfigurer {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
http.authorizeHttpRequests(auth -> auth
.anyRequest()
.authenticated())
.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable());
return http.build();
}

View File

@ -1,10 +1,9 @@
package com.baeldung.methodsecurity.service;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.security.RolesAllowed;
import com.baeldung.methodsecurity.annotation.IsViewer;
import com.baeldung.methodsecurity.entity.CustomUser;
import com.baeldung.methodsecurity.repository.UserRoleRepository;
import jakarta.annotation.security.RolesAllowed;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
@ -15,9 +14,8 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import com.baeldung.methodsecurity.annotation.IsViewer;
import com.baeldung.methodsecurity.entity.CustomUser;
import com.baeldung.methodsecurity.repository.UserRoleRepository;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserRoleService {

View File

@ -1,14 +1,9 @@
package com.baeldung.denyonmissing;
import static org.hamcrest.core.Is.isA;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import jakarta.servlet.ServletException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.jupiter.api.Assertions;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@ -19,12 +14,13 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DenyApplication.class)
public class DenyOnMissingControllerIntegrationTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@ -46,8 +42,11 @@ public class DenyOnMissingControllerIntegrationTest {
@Test
@WithMockUser(username = "user")
public void givenANormalUser_whenCallingBye_thenAccessDenied() throws Exception {
expectedException.expectCause(isA(AccessDeniedException.class));
ServletException exception = Assertions.assertThrows(ServletException.class, () -> {
mockMvc.perform(get("/bye"));
});
mockMvc.perform(get("/bye"));
Assertions.assertNotNull(exception);
Assertions.assertEquals(exception.getCause().getClass(), AccessDeniedException.class);
}
}

View File

@ -1,12 +1,10 @@
package com.baeldung.filterresponse;
import com.baeldung.filterresponse.config.AppConfig;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import jakarta.servlet.ServletException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.jupiter.api.Assertions;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.test.context.support.WithMockUser;
@ -16,8 +14,8 @@ import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.util.NestedServletException;
import static org.junit.jupiter.api.Assertions.assertTrue;
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;
@ -32,9 +30,6 @@ public class SpringSecurityJsonViewIntegrationTest {
private MockMvc mvc;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
public void setup() {
mvc = MockMvcBuilders
@ -65,21 +60,12 @@ public class SpringSecurityJsonViewIntegrationTest {
@Test
@WithMockUser(username = "user", password = "userPass", roles = {"ADMIN", "USER"})
public void whenMultipleRoles_thenExceptionIsThrown() throws Exception {
expectedException.expect(new BaseMatcher<NestedServletException>() {
@Override
public boolean matches(Object o) {
NestedServletException exception = (NestedServletException) o;
return exception.getCause() instanceof IllegalArgumentException && exception.getCause().getMessage().equals("Ambiguous @JsonView declaration for roles ROLE_ADMIN,ROLE_USER");
}
@Override
public void describeTo(Description description) {
}
ServletException exception = Assertions.assertThrows(ServletException.class, () -> {
mvc.perform(get("/items"))
.andExpect(status().isOk());
});
mvc.perform(get("/items"))
.andExpect(status().isOk());
Assertions.assertEquals(exception.getCause().getClass(), IllegalArgumentException.class);
assertTrue(exception.getCause().getMessage().equals("Ambiguous @JsonView declaration for roles ROLE_ADMIN,ROLE_USER"));
}
}