浏览代码

Default Require Explicit Save SecurityContext

Closes gh-11762
Rob Winch 3 年之前
父节点
当前提交
2efc8dcd15

+ 1 - 1
config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java

@@ -323,7 +323,7 @@ class HttpConfigurationBuilder {
 
 
 	private boolean isExplicitSave() {
 	private boolean isExplicitSave() {
 		String explicitSaveAttr = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_EXPLICIT_SAVE);
 		String explicitSaveAttr = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_EXPLICIT_SAVE);
-		return Boolean.parseBoolean(explicitSaveAttr);
+		return !StringUtils.hasText(explicitSaveAttr) || Boolean.parseBoolean(explicitSaveAttr);
 	}
 	}
 
 
 	private void createForceEagerSessionCreationFilter() {
 	private void createForceEagerSessionCreationFilter() {

+ 0 - 4
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(clientRegistrationRepository).addConstructorArgValue(authorizedClientRepository)
 				.addConstructorArgValue(this.authenticationManager)
 				.addConstructorArgValue(this.authenticationManager)
 				.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository);
 				.addPropertyValue("authorizationRequestRepository", authorizationRequestRepository);
-		if (this.authenticationFilterSecurityContextRepositoryRef != null) {
-			authorizationCodeGrantFilterBldr.addPropertyValue("securityContextRepository",
-					this.authenticationFilterSecurityContextRepositoryRef);
-		}
 		this.authorizationCodeGrantFilter = authorizationCodeGrantFilterBldr.getBeanDefinition();
 		this.authorizationCodeGrantFilter = authorizationCodeGrantFilterBldr.getBeanDefinition();
 
 
 		BeanMetadataElement accessTokenResponseClient = getAccessTokenResponseClient(authorizationCodeGrantElt);
 		BeanMetadataElement accessTokenResponseClient = getAccessTokenResponseClient(authorizationCodeGrantElt);

+ 1 - 1
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.
 	## 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}?
 	attribute security-context-repository-ref {xsd:token}?
 http.attlist &=
 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}?
 	attribute security-context-explicit-save {xsd:boolean}?
 http.attlist &=
 http.attlist &=
 	request-matcher?
 	request-matcher?

+ 0 - 3
config/src/test/java/org/springframework/security/config/annotation/web/configuration/DeferHttpSessionJavaConfigTests.java

@@ -82,9 +82,6 @@ public class DeferHttpSessionJavaConfigTests {
 			csrfRepository.setDeferLoadToken(true);
 			csrfRepository.setDeferLoadToken(true);
 			// @formatter:off
 			// @formatter:off
 			http
 			http
-				.securityContext((securityContext) -> securityContext
-					.requireExplicitSave(true)
-				)
 				.authorizeHttpRequests((requests) -> requests
 				.authorizeHttpRequests((requests) -> requests
 					.anyRequest().permitAll()
 					.anyRequest().permitAll()
 				)
 				)

+ 4 - 4
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.ui.DefaultLogoutPageGeneratingFilter;
 import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
 import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
 import org.springframework.security.web.context.HttpRequestResponseHolder;
 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.SecurityContextRepository;
 import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
 import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
 import org.springframework.security.web.csrf.CsrfFilter;
 import org.springframework.security.web.csrf.CsrfFilter;
@@ -356,7 +356,7 @@ public class MiscHttpConfigTests {
 		List<Filter> filters = getFilters("/");
 		List<Filter> filters = getFilters("/");
 		Class<?> userFilterClass = this.spring.getContext().getBean("userFilter").getClass();
 		Class<?> userFilterClass = this.spring.getContext().getBean("userFilter").getClass();
 		assertThat(filters).extracting((Extractor<Filter, Class<?>>) (filter) -> filter.getClass()).containsSubsequence(
 		assertThat(filters).extracting((Extractor<Filter, Class<?>>) (filter) -> filter.getClass()).containsSubsequence(
-				userFilterClass, userFilterClass, SecurityContextPersistenceFilter.class, LogoutFilter.class,
+				userFilterClass, userFilterClass, SecurityContextHolderFilter.class, LogoutFilter.class,
 				userFilterClass);
 				userFilterClass);
 	}
 	}
 
 
@@ -472,7 +472,7 @@ public class MiscHttpConfigTests {
 		this.spring.configLocations(xml("SecurityContextRepository")).autowire();
 		this.spring.configLocations(xml("SecurityContextRepository")).autowire();
 		SecurityContextRepository repository = this.spring.getContext().getBean(SecurityContextRepository.class);
 		SecurityContextRepository repository = this.spring.getContext().getBean(SecurityContextRepository.class);
 		SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "password"));
 		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
 		// @formatter:off
 		MvcResult result = this.mvc.perform(get("/protected").with(userCredentials()))
 		MvcResult result = this.mvc.perform(get("/protected").with(userCredentials()))
 				.andExpect(status().isOk())
 				.andExpect(status().isOk())
@@ -839,7 +839,7 @@ public class MiscHttpConfigTests {
 	private void assertThatFiltersMatchExpectedAutoConfigList(String url) {
 	private void assertThatFiltersMatchExpectedAutoConfigList(String url) {
 		Iterator<Filter> filters = getFilters(url).iterator();
 		Iterator<Filter> filters = getFilters(url).iterator();
 		assertThat(filters.next()).isInstanceOf(DisableEncodeUrlFilter.class);
 		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(WebAsyncManagerIntegrationFilter.class);
 		assertThat(filters.next()).isInstanceOf(HeaderWriterFilter.class);
 		assertThat(filters.next()).isInstanceOf(HeaderWriterFilter.class);
 		assertThat(filters.next()).isInstanceOf(CsrfFilter.class);
 		assertThat(filters.next()).isInstanceOf(CsrfFilter.class);

+ 0 - 1
config/src/test/resources/org/springframework/security/config/http/DeferHttpSessionTests-Explicit.xml

@@ -27,7 +27,6 @@
 	<b:bean class="org.springframework.security.config.http.DeferHttpSessionXmlConfigTests$Service" />
 	<b:bean class="org.springframework.security.config.http.DeferHttpSessionXmlConfigTests$Service" />
 
 
 	<http auto-config="true"
 	<http auto-config="true"
-			security-context-explicit-save="true"
 			use-authorization-manager="true">
 			use-authorization-manager="true">
 		<intercept-url  pattern="/**" access="permitAll"/>
 		<intercept-url  pattern="/**" access="permitAll"/>
 		<csrf request-attribute-name="_csrf"
 		<csrf request-attribute-name="_csrf"

+ 6 - 1
web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java

@@ -45,6 +45,7 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
 import org.springframework.security.web.authentication.logout.LogoutHandler;
 import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.security.web.context.SecurityContextRepository;
 import org.springframework.util.Assert;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.CollectionUtils;
 
 
@@ -92,8 +93,11 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
 
 
 	private List<LogoutHandler> logoutHandlers;
 	private List<LogoutHandler> logoutHandlers;
 
 
-	HttpServlet3RequestFactory(String rolePrefix) {
+	private SecurityContextRepository securityContextRepository;
+
+	HttpServlet3RequestFactory(String rolePrefix, SecurityContextRepository securityContextRepository) {
 		this.rolePrefix = rolePrefix;
 		this.rolePrefix = rolePrefix;
+		this.securityContextRepository = securityContextRepository;
 	}
 	}
 
 
 	/**
 	/**
@@ -244,6 +248,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
 					.createEmptyContext();
 					.createEmptyContext();
 			context.setAuthentication(authentication);
 			context.setAuthentication(authentication);
 			HttpServlet3RequestFactory.this.securityContextHolderStrategy.setContext(context);
 			HttpServlet3RequestFactory.this.securityContextHolderStrategy.setContext(context);
+			HttpServlet3RequestFactory.this.securityContextRepository.saveContext(context, this, this.response);
 		}
 		}
 
 
 		private Authentication getAuthentication(AuthenticationManager authManager, String username, String password)
 		private Authentication getAuthentication(AuthenticationManager authManager, String username, String password)

+ 15 - 1
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.core.context.SecurityContextHolderStrategy;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.authentication.logout.LogoutHandler;
 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.util.Assert;
 import org.springframework.web.filter.GenericFilterBean;
 import org.springframework.web.filter.GenericFilterBean;
 
 
@@ -84,6 +86,18 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
 
 
 	private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
 	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
 	 * Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
 	 * the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
 	 * the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
@@ -188,7 +202,7 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
 	}
 	}
 
 
 	private HttpServletRequestFactory createServlet3Factory(String rolePrefix) {
 	private HttpServletRequestFactory createServlet3Factory(String rolePrefix) {
-		HttpServlet3RequestFactory factory = new HttpServlet3RequestFactory(rolePrefix);
+		HttpServlet3RequestFactory factory = new HttpServlet3RequestFactory(rolePrefix, this.securityContextRepository);
 		factory.setTrustResolver(this.trustResolver);
 		factory.setTrustResolver(this.trustResolver);
 		factory.setAuthenticationEntryPoint(this.authenticationEntryPoint);
 		factory.setAuthenticationEntryPoint(this.authenticationEntryPoint);
 		factory.setAuthenticationManager(this.authenticationManager);
 		factory.setAuthenticationManager(this.authenticationManager);