diff --git a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java index a7c4fe39d5..f4236e3989 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java @@ -323,7 +323,7 @@ class HttpConfigurationBuilder { private boolean isExplicitSave() { String explicitSaveAttr = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_EXPLICIT_SAVE); - return Boolean.parseBoolean(explicitSaveAttr); + return !StringUtils.hasText(explicitSaveAttr) || Boolean.parseBoolean(explicitSaveAttr); } private void createForceEagerSessionCreationFilter() { diff --git a/config/src/main/java/org/springframework/security/config/http/OAuth2ClientBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/OAuth2ClientBeanDefinitionParser.java index 5f039548fe..30985d08b2 100644 --- a/config/src/main/java/org/springframework/security/config/http/OAuth2ClientBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/OAuth2ClientBeanDefinitionParser.java @@ -105,10 +105,6 @@ final class OAuth2ClientBeanDefinitionParser implements BeanDefinitionParser { .addConstructorArgValue(clientRegistrationRepository).addConstructorArgValue(authorizedClientRepository) .addConstructorArgValue(this.authenticationManager) .addPropertyValue("authorizationRequestRepository", authorizationRequestRepository); - if (this.authenticationFilterSecurityContextRepositoryRef != null) { - authorizationCodeGrantFilterBldr.addPropertyValue("securityContextRepository", - this.authenticationFilterSecurityContextRepositoryRef); - } this.authorizationCodeGrantFilter = authorizationCodeGrantFilterBldr.getBeanDefinition(); BeanMetadataElement accessTokenResponseClient = getAccessTokenResponseClient(authorizationCodeGrantElt); diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc index 996ab66dd1..1620524522 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-6.0.rnc @@ -354,7 +354,7 @@ http.attlist &= ## A reference to a SecurityContextRepository bean. This can be used to customize how the SecurityContext is stored between requests. attribute security-context-repository-ref {xsd:token}? http.attlist &= - ## Optional attribute that specifies that the SecurityContext should require explicit saving rather than being synchronized from the SecurityContextHolder. Defaults to "false". + ## Optional attribute that specifies that the SecurityContext should require explicit saving rather than being synchronized from the SecurityContextHolder. Defaults to "true". attribute security-context-explicit-save {xsd:boolean}? http.attlist &= request-matcher? diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/DeferHttpSessionJavaConfigTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/DeferHttpSessionJavaConfigTests.java index e499b510db..89eabe1237 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/DeferHttpSessionJavaConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/DeferHttpSessionJavaConfigTests.java @@ -82,9 +82,6 @@ public class DeferHttpSessionJavaConfigTests { csrfRepository.setDeferLoadToken(true); // @formatter:off http - .securityContext((securityContext) -> securityContext - .requireExplicitSave(true) - ) .authorizeHttpRequests((requests) -> requests .anyRequest().permitAll() ) diff --git a/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java b/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java index eb4879aa21..dfbeee75a5 100644 --- a/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java +++ b/config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java @@ -93,7 +93,7 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.context.HttpRequestResponseHolder; -import org.springframework.security.web.context.SecurityContextPersistenceFilter; +import org.springframework.security.web.context.SecurityContextHolderFilter; import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter; import org.springframework.security.web.csrf.CsrfFilter; @@ -356,7 +356,7 @@ public class MiscHttpConfigTests { List filters = getFilters("/"); Class userFilterClass = this.spring.getContext().getBean("userFilter").getClass(); assertThat(filters).extracting((Extractor>) (filter) -> filter.getClass()).containsSubsequence( - userFilterClass, userFilterClass, SecurityContextPersistenceFilter.class, LogoutFilter.class, + userFilterClass, userFilterClass, SecurityContextHolderFilter.class, LogoutFilter.class, userFilterClass); } @@ -472,7 +472,7 @@ public class MiscHttpConfigTests { this.spring.configLocations(xml("SecurityContextRepository")).autowire(); SecurityContextRepository repository = this.spring.getContext().getBean(SecurityContextRepository.class); SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "password")); - given(repository.loadContext(any(HttpRequestResponseHolder.class))).willReturn(context); + given(repository.loadContext(any(HttpServletRequest.class))).willReturn(() -> context); // @formatter:off MvcResult result = this.mvc.perform(get("/protected").with(userCredentials())) .andExpect(status().isOk()) @@ -839,7 +839,7 @@ public class MiscHttpConfigTests { private void assertThatFiltersMatchExpectedAutoConfigList(String url) { Iterator filters = getFilters(url).iterator(); assertThat(filters.next()).isInstanceOf(DisableEncodeUrlFilter.class); - assertThat(filters.next()).isInstanceOf(SecurityContextPersistenceFilter.class); + assertThat(filters.next()).isInstanceOf(SecurityContextHolderFilter.class); assertThat(filters.next()).isInstanceOf(WebAsyncManagerIntegrationFilter.class); assertThat(filters.next()).isInstanceOf(HeaderWriterFilter.class); assertThat(filters.next()).isInstanceOf(CsrfFilter.class); diff --git a/config/src/test/resources/org/springframework/security/config/http/DeferHttpSessionTests-Explicit.xml b/config/src/test/resources/org/springframework/security/config/http/DeferHttpSessionTests-Explicit.xml index 9be33976ba..2c0adca4d0 100644 --- a/config/src/test/resources/org/springframework/security/config/http/DeferHttpSessionTests-Explicit.xml +++ b/config/src/test/resources/org/springframework/security/config/http/DeferHttpSessionTests-Explicit.xml @@ -27,7 +27,6 @@ logoutHandlers; - HttpServlet3RequestFactory(String rolePrefix) { + private SecurityContextRepository securityContextRepository; + + HttpServlet3RequestFactory(String rolePrefix, SecurityContextRepository securityContextRepository) { this.rolePrefix = rolePrefix; + this.securityContextRepository = securityContextRepository; } /** @@ -244,6 +248,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory { .createEmptyContext(); context.setAuthentication(authentication); HttpServlet3RequestFactory.this.securityContextHolderStrategy.setContext(context); + HttpServlet3RequestFactory.this.securityContextRepository.saveContext(context, this, this.response); } private Authentication getAuthentication(AuthenticationManager authManager, String username, String password) diff --git a/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java b/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java index 22673b8453..3bee604088 100644 --- a/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java +++ b/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java @@ -35,6 +35,8 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.logout.LogoutHandler; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; +import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.util.Assert; import org.springframework.web.filter.GenericFilterBean; @@ -84,6 +86,18 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean { private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); + private SecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository(); + + /** + * Sets the {@link SecurityContextRepository} to use. The default is to use {@link HttpSessionSecurityContextRepository}. + * @param securityContextRepository the {@link SecurityContextRepository} to use. + * @since 6.0 + */ + public void setSecurityContextRepository(SecurityContextRepository securityContextRepository) { + Assert.notNull(securityContextRepository, "securityContextRepository cannot be null"); + this.securityContextRepository = securityContextRepository; + } + /** * Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use * the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}. @@ -188,7 +202,7 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean { } private HttpServletRequestFactory createServlet3Factory(String rolePrefix) { - HttpServlet3RequestFactory factory = new HttpServlet3RequestFactory(rolePrefix); + HttpServlet3RequestFactory factory = new HttpServlet3RequestFactory(rolePrefix, this.securityContextRepository); factory.setTrustResolver(this.trustResolver); factory.setAuthenticationEntryPoint(this.authenticationEntryPoint); factory.setAuthenticationManager(this.authenticationManager);