@ -16,6 +16,14 @@
@@ -16,6 +16,14 @@
package org.springframework.security.config.annotation.web.configurers ;
import java.io.IOException ;
import jakarta.servlet.DispatcherType ;
import jakarta.servlet.Filter ;
import jakarta.servlet.FilterChain ;
import jakarta.servlet.ServletException ;
import jakarta.servlet.ServletRequest ;
import jakarta.servlet.ServletResponse ;
import jakarta.servlet.http.HttpServletRequest ;
import jakarta.servlet.http.HttpServletResponse ;
import jakarta.servlet.http.HttpSession ;
@ -25,8 +33,13 @@ import org.junit.jupiter.api.extension.ExtendWith;
@@ -25,8 +33,13 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired ;
import org.springframework.context.annotation.Bean ;
import org.springframework.context.annotation.Configuration ;
import org.springframework.http.HttpStatus ;
import org.springframework.http.ResponseEntity ;
import org.springframework.mock.web.MockFilterChain ;
import org.springframework.mock.web.MockHttpServletRequest ;
import org.springframework.mock.web.MockHttpSession ;
import org.springframework.security.authentication.AuthenticationTrustResolver ;
import org.springframework.security.config.Customizer ;
import org.springframework.security.config.TestDeferredSecurityContext ;
import org.springframework.security.config.annotation.ObjectPostProcessor ;
import org.springframework.security.config.annotation.web.builders.HttpSecurity ;
@ -55,8 +68,10 @@ import org.springframework.test.web.servlet.MockMvc;
@@ -55,8 +68,10 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult ;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder ;
import org.springframework.test.web.servlet.setup.MockMvcBuilders ;
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.util.WebUtils ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.mockito.ArgumentMatchers.any ;
@ -360,6 +375,84 @@ public class SessionManagementConfigurerTests {
@@ -360,6 +375,84 @@ public class SessionManagementConfigurerTests {
assertThat ( securityContext ) . isNotNull ( ) ;
}
/ * *
* This ensures that if an ErrorDispatch occurs , then the SecurityContextRepository
* defaulted by SessionManagementConfigurer is correct ( looks at both Session and
* Request Attributes ) .
* @throws Exception
* /
@Test
public void gh12070WhenErrorDispatchSecurityContextRepositoryWorks ( ) throws Exception {
Filter errorDispatchFilter = new Filter ( ) {
@Override
public void doFilter ( ServletRequest request , ServletResponse response , FilterChain chain )
throws IOException , ServletException {
try {
chain . doFilter ( request , response ) ;
}
catch ( ServletException ex ) {
if ( request . getDispatcherType ( ) = = DispatcherType . ERROR ) {
throw ex ;
}
MockHttpServletRequest httpRequest = WebUtils . getNativeRequest ( request ,
MockHttpServletRequest . class ) ;
httpRequest . setDispatcherType ( DispatcherType . ERROR ) ;
// necessary to prevent HttpBasicFilter from invoking again
httpRequest . setAttribute ( WebUtils . ERROR_REQUEST_URI_ATTRIBUTE , "/error" ) ;
httpRequest . setRequestURI ( "/error" ) ;
MockFilterChain mockChain = ( MockFilterChain ) chain ;
mockChain . reset ( ) ;
mockChain . doFilter ( httpRequest , response ) ;
}
}
} ;
this . spring . addFilter ( errorDispatchFilter ) . register ( Gh12070IssueConfig . class ) . autowire ( ) ;
// @formatter:off
this . mvc . perform ( get ( "/500" ) . with ( httpBasic ( "user" , "password" ) ) )
. andExpect ( status ( ) . isInternalServerError ( ) ) ;
// @formatter:on
}
@Configuration
@EnableWebSecurity
static class Gh12070IssueConfig {
@Bean
SecurityFilterChain filterChain ( HttpSecurity http ) throws Exception {
// @formatter:off
http
. authorizeHttpRequests ( ( authorize ) - > authorize
. anyRequest ( ) . authenticated ( )
)
. httpBasic ( Customizer . withDefaults ( ) )
. formLogin ( Customizer . withDefaults ( ) ) ;
return http . build ( ) ;
// @formatter:on
}
@Bean
UserDetailsService userDetailsService ( ) {
return new InMemoryUserDetailsManager ( PasswordEncodedUser . user ( ) ) ;
}
@RestController
static class ErrorController {
@GetMapping ( "/500" )
String error ( ) throws ServletException {
throw new ServletException ( "Error" ) ;
}
@GetMapping ( "/error" )
ResponseEntity < String > errorHandler ( ) {
return new ResponseEntity < > ( "error" , HttpStatus . INTERNAL_SERVER_ERROR ) ;
}
}
}
@Configuration
@EnableWebSecurity
static class SessionManagementRequestCacheConfig {