ForceEagerSessionCreationFilter

Closes gh-11109
This commit is contained in:
Rob Winch 2022-04-15 13:55:54 -05:00
parent 7fea639a43
commit aaf78330b1
14 changed files with 181 additions and 31 deletions

View File

@ -43,6 +43,7 @@ import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter; import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter; import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter; import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.SessionManagementFilter; import org.springframework.security.web.session.SessionManagementFilter;
/** /**
@ -125,6 +126,7 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
* The ordering of the Filters is: * The ordering of the Filters is:
* *
* <ul> * <ul>
* <li>{@link ForceEagerSessionCreationFilter}</li>
* <li>{@link DisableEncodeUrlFilter}</li> * <li>{@link DisableEncodeUrlFilter}</li>
* <li>{@link ChannelProcessingFilter}</li> * <li>{@link ChannelProcessingFilter}</li>
* <li>{@link SecurityContextPersistenceFilter}</li> * <li>{@link SecurityContextPersistenceFilter}</li>

View File

@ -47,6 +47,7 @@ import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter; import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter; import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter; import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.SessionManagementFilter; import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.web.filter.CorsFilter; import org.springframework.web.filter.CorsFilter;
@ -70,6 +71,7 @@ final class FilterOrderRegistration {
FilterOrderRegistration() { FilterOrderRegistration() {
Step order = new Step(INITIAL_ORDER, ORDER_STEP); Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(DisableEncodeUrlFilter.class, order.next()); put(DisableEncodeUrlFilter.class, order.next());
put(ForceEagerSessionCreationFilter.class, order.next());
put(ChannelProcessingFilter.class, order.next()); put(ChannelProcessingFilter.class, order.next());
order.next(); // gh-8105 order.next(); // gh-8105
put(WebAsyncManagerIntegrationFilter.class, order.next()); put(WebAsyncManagerIntegrationFilter.class, order.next());

View File

@ -25,6 +25,7 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
import org.springframework.security.web.context.SecurityContextHolderFilter; import org.springframework.security.web.context.SecurityContextHolderFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter; import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
/** /**
* Allows persisting and restoring of the {@link SecurityContext} found on the * Allows persisting and restoring of the {@link SecurityContext} found on the
@ -117,6 +118,7 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
? sessionManagement.getSessionCreationPolicy() : null; ? sessionManagement.getSessionCreationPolicy() : null;
if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) { if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
securityContextFilter.setForceEagerSessionCreation(true); securityContextFilter.setForceEagerSessionCreation(true);
http.addFilter(postProcess(new ForceEagerSessionCreationFilter()));
} }
securityContextFilter = postProcess(securityContextFilter); securityContextFilter = postProcess(securityContextFilter);
http.addFilter(securityContextFilter); http.addFilter(securityContextFilter);

View File

@ -53,6 +53,7 @@ import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.session.ConcurrentSessionFilter; import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter; import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.InvalidSessionStrategy; import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy; import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.security.web.session.SessionManagementFilter; import org.springframework.security.web.session.SessionManagementFilter;
@ -380,6 +381,9 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
if (!this.enableSessionUrlRewriting) { if (!this.enableSessionUrlRewriting) {
http.addFilter(new DisableEncodeUrlFilter()); http.addFilter(new DisableEncodeUrlFilter());
} }
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
http.addFilter(new ForceEagerSessionCreationFilter());
}
} }
private ConcurrentSessionFilter createConcurrencyFilter(H http) { private ConcurrentSessionFilter createConcurrencyFilter(H http) {

View File

@ -69,6 +69,7 @@ import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter; import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter; import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.DisableEncodeUrlFilter; import org.springframework.security.web.session.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
import org.springframework.security.web.session.SessionManagementFilter; import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy; import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy; import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy;
@ -148,6 +149,8 @@ class HttpConfigurationBuilder {
private BeanDefinition securityContextPersistenceFilter; private BeanDefinition securityContextPersistenceFilter;
private BeanDefinition forceEagerSessionCreationFilter;
private BeanReference contextRepoRef; private BeanReference contextRepoRef;
private BeanReference sessionRegistryRef; private BeanReference sessionRegistryRef;
@ -207,6 +210,7 @@ class HttpConfigurationBuilder {
String createSession = element.getAttribute(ATT_CREATE_SESSION); String createSession = element.getAttribute(ATT_CREATE_SESSION);
this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED
: createPolicy(createSession); : createPolicy(createSession);
createForceEagerSessionCreationFilter();
createDisableEncodeUrlFilter(); createDisableEncodeUrlFilter();
createCsrfFilter(); createCsrfFilter();
createSecurityPersistence(); createSecurityPersistence();
@ -304,6 +308,12 @@ class HttpConfigurationBuilder {
return Boolean.parseBoolean(explicitSaveAttr); return Boolean.parseBoolean(explicitSaveAttr);
} }
private void createForceEagerSessionCreationFilter() {
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
this.forceEagerSessionCreationFilter = new RootBeanDefinition(ForceEagerSessionCreationFilter.class);
}
}
private void createSecurityContextPersistenceFilter() { private void createSecurityContextPersistenceFilter() {
BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class); BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class);
switch (this.sessionPolicy) { switch (this.sessionPolicy) {
@ -768,6 +778,10 @@ class HttpConfigurationBuilder {
List<OrderDecorator> getFilters() { List<OrderDecorator> getFilters() {
List<OrderDecorator> filters = new ArrayList<>(); List<OrderDecorator> filters = new ArrayList<>();
if (this.forceEagerSessionCreationFilter != null) {
filters.add(new OrderDecorator(this.forceEagerSessionCreationFilter,
SecurityFilters.FORCE_EAGER_SESSION_FILTER));
}
if (this.disableUrlRewriteFilter != null) { if (this.disableUrlRewriteFilter != null) {
filters.add(new OrderDecorator(this.disableUrlRewriteFilter, SecurityFilters.DISABLE_ENCODE_URL_FILTER)); filters.add(new OrderDecorator(this.disableUrlRewriteFilter, SecurityFilters.DISABLE_ENCODE_URL_FILTER));
} }

View File

@ -31,6 +31,8 @@ enum SecurityFilters {
DISABLE_ENCODE_URL_FILTER, DISABLE_ENCODE_URL_FILTER,
FORCE_EAGER_SESSION_FILTER,
CHANNEL_FILTER, CHANNEL_FILTER,
SECURITY_CONTEXT_FILTER, SECURITY_CONTEXT_FILTER,

View File

@ -1318,4 +1318,4 @@ position =
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter. ## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
attribute position {named-security-filter} attribute position {named-security-filter}
named-security-filter = "FIRST" | "DISABLE_ENCODE_URL_FILTER" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "SAML2_LOGOUT_REQUEST_FILTER" | "SAML2_LOGOUT_RESPONSE_FILTER" | "CSRF_FILTER" | "SAML2_LOGOUT_FILTER" | "LOGOUT_FILTER" | "OAUTH2_AUTHORIZATION_REQUEST_FILTER" | "SAML2_AUTHENTICATION_REQUEST_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "SAML2_AUTHENTICATION_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" |"LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER" | "WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST" named-security-filter = "FIRST" | "DISABLE_ENCODE_URL_FILTER" | "FORCE_EAGER_SESSION_FILTER" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CORS_FILTER" | "SAML2_LOGOUT_REQUEST_FILTER" | "SAML2_LOGOUT_RESPONSE_FILTER" | "CSRF_FILTER" | "SAML2_LOGOUT_FILTER" | "LOGOUT_FILTER" | "OAUTH2_AUTHORIZATION_REQUEST_FILTER" | "SAML2_AUTHENTICATION_REQUEST_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "OAUTH2_LOGIN_FILTER" | "SAML2_AUTHENTICATION_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" |"LOGOUT_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BEARER_TOKEN_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER" | "WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"

View File

@ -124,7 +124,7 @@
</xs:annotation> </xs:annotation>
<xs:complexType/> <xs:complexType/>
</xs:element> </xs:element>
<xs:attributeGroup name="password-encoder.attlist"> <xs:attributeGroup name="password-encoder.attlist">
<xs:attribute name="ref" type="xs:token"> <xs:attribute name="ref" type="xs:token">
<xs:annotation> <xs:annotation>
@ -408,7 +408,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="ldap-ap.attlist"> <xs:attributeGroup name="ldap-ap.attlist">
<xs:attribute name="server-ref" type="xs:token"> <xs:attribute name="server-ref" type="xs:token">
<xs:annotation> <xs:annotation>
@ -488,7 +488,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="password-compare.attlist"> <xs:attributeGroup name="password-compare.attlist">
<xs:attribute name="password-attribute" type="xs:token"> <xs:attribute name="password-attribute" type="xs:token">
<xs:annotation> <xs:annotation>
@ -541,7 +541,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="protect.attlist"> <xs:attributeGroup name="protect.attlist">
<xs:attribute name="method" use="required" type="xs:token"> <xs:attribute name="method" use="required" type="xs:token">
<xs:annotation> <xs:annotation>
@ -842,13 +842,13 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="protect-pointcut.attlist"> <xs:attributeGroup name="protect-pointcut.attlist">
<xs:attribute name="expression" use="required" type="xs:string"> <xs:attribute name="expression" use="required" type="xs:string">
<xs:annotation> <xs:annotation>
@ -1323,7 +1323,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="access-denied-handler.attlist"> <xs:attributeGroup name="access-denied-handler.attlist">
<xs:attribute name="ref" type="xs:token"> <xs:attribute name="ref" type="xs:token">
<xs:annotation> <xs:annotation>
@ -1348,7 +1348,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="intercept-url.attlist"> <xs:attributeGroup name="intercept-url.attlist">
<xs:attribute name="pattern" type="xs:token"> <xs:attribute name="pattern" type="xs:token">
<xs:annotation> <xs:annotation>
@ -1405,7 +1405,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="logout.attlist"> <xs:attributeGroup name="logout.attlist">
<xs:attribute name="logout-url" type="xs:token"> <xs:attribute name="logout-url" type="xs:token">
<xs:annotation> <xs:annotation>
@ -1452,7 +1452,7 @@
<xs:attributeGroup ref="security:ref"/> <xs:attributeGroup ref="security:ref"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="form-login.attlist"> <xs:attributeGroup name="form-login.attlist">
<xs:attribute name="login-processing-url" type="xs:token"> <xs:attribute name="login-processing-url" type="xs:token">
<xs:annotation> <xs:annotation>
@ -1967,7 +1967,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="attribute-exchange"> <xs:element name="attribute-exchange">
<xs:annotation> <xs:annotation>
<xs:documentation>Sets up an attribute exchange configuration to request specified attributes from the <xs:documentation>Sets up an attribute exchange configuration to request specified attributes from the
@ -2034,7 +2034,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="saml2-login.attlist"> <xs:attributeGroup name="saml2-login.attlist">
<xs:attribute name="relying-party-registration-repository-ref" type="xs:token"> <xs:attribute name="relying-party-registration-repository-ref" type="xs:token">
<xs:annotation> <xs:annotation>
@ -2091,7 +2091,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="saml2-logout.attlist"> <xs:attributeGroup name="saml2-logout.attlist">
<xs:attribute name="logout-url" type="xs:token"> <xs:attribute name="logout-url" type="xs:token">
<xs:annotation> <xs:annotation>
@ -2544,7 +2544,7 @@
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="http-basic.attlist"> <xs:attributeGroup name="http-basic.attlist">
<xs:attribute name="entry-point-ref" type="xs:token"> <xs:attribute name="entry-point-ref" type="xs:token">
<xs:annotation> <xs:annotation>
@ -2577,7 +2577,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="session-management.attlist"> <xs:attributeGroup name="session-management.attlist">
<xs:attribute name="session-fixation-protection"> <xs:attribute name="session-fixation-protection">
<xs:annotation> <xs:annotation>
@ -2633,7 +2633,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="concurrency-control.attlist"> <xs:attributeGroup name="concurrency-control.attlist">
<xs:attribute name="max-sessions" type="xs:token"> <xs:attribute name="max-sessions" type="xs:token">
<xs:annotation> <xs:annotation>
@ -2680,7 +2680,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="remember-me.attlist"> <xs:attributeGroup name="remember-me.attlist">
<xs:attribute name="key" type="xs:token"> <xs:attribute name="key" type="xs:token">
<xs:annotation> <xs:annotation>
@ -2778,7 +2778,7 @@
<xs:attributeGroup name="remember-me-data-source-ref"> <xs:attributeGroup name="remember-me-data-source-ref">
<xs:attributeGroup ref="security:data-source-ref"/> <xs:attributeGroup ref="security:data-source-ref"/>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="anonymous.attlist"> <xs:attributeGroup name="anonymous.attlist">
<xs:attribute name="key" type="xs:token"> <xs:attribute name="key" type="xs:token">
<xs:annotation> <xs:annotation>
@ -2811,8 +2811,8 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="http-port"> <xs:attributeGroup name="http-port">
<xs:attribute name="http" use="required" type="xs:token"> <xs:attribute name="http" use="required" type="xs:token">
<xs:annotation> <xs:annotation>
@ -2829,7 +2829,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="x509.attlist"> <xs:attributeGroup name="x509.attlist">
<xs:attribute name="subject-principal-regex" type="xs:token"> <xs:attribute name="subject-principal-regex" type="xs:token">
<xs:annotation> <xs:annotation>
@ -2966,7 +2966,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="ap.attlist"> <xs:attributeGroup name="ap.attlist">
<xs:attribute name="ref" type="xs:token"> <xs:attribute name="ref" type="xs:token">
<xs:annotation> <xs:annotation>
@ -3018,7 +3018,7 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="user.attlist"> <xs:attributeGroup name="user.attlist">
<xs:attribute name="name" use="required" type="xs:token"> <xs:attribute name="name" use="required" type="xs:token">
<xs:annotation> <xs:annotation>
@ -3721,6 +3721,7 @@
<xs:restriction base="xs:token"> <xs:restriction base="xs:token">
<xs:enumeration value="FIRST"/> <xs:enumeration value="FIRST"/>
<xs:enumeration value="DISABLE_ENCODE_URL_FILTER"/> <xs:enumeration value="DISABLE_ENCODE_URL_FILTER"/>
<xs:enumeration value="FORCE_EAGER_SESSION_FILTER"/>
<xs:enumeration value="CHANNEL_FILTER"/> <xs:enumeration value="CHANNEL_FILTER"/>
<xs:enumeration value="SECURITY_CONTEXT_FILTER"/> <xs:enumeration value="SECURITY_CONTEXT_FILTER"/>
<xs:enumeration value="CONCURRENT_SESSION_FILTER"/> <xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
@ -3760,4 +3761,4 @@
<xs:enumeration value="LAST"/> <xs:enumeration value="LAST"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:schema> </xs:schema>

View File

@ -53,7 +53,7 @@ public class FilterOrderRegistrationTests {
@Test @Test
public void putWhenPredefinedFilterThenDoesNotOverride() { public void putWhenPredefinedFilterThenDoesNotOverride() {
int position = 200; int position = 300;
Integer predefinedFilterOrderBefore = this.filterOrderRegistration.getOrder(ChannelProcessingFilter.class); Integer predefinedFilterOrderBefore = this.filterOrderRegistration.getOrder(ChannelProcessingFilter.class);
this.filterOrderRegistration.put(MyFilter.class, position); this.filterOrderRegistration.put(MyFilter.class, position);
Integer myFilterOrder = this.filterOrderRegistration.getOrder(MyFilter.class); Integer myFilterOrder = this.filterOrderRegistration.getOrder(MyFilter.class);

View File

@ -165,6 +165,7 @@ However, there are times that it is beneficial to know the ordering
Below is a comprehensive list of Spring Security Filter ordering: Below is a comprehensive list of Spring Security Filter ordering:
* xref:servlet/authentication/session-management.adoc#session-mgmt-force-session-creation[`ForceEagerSessionCreationFilter`]
* ChannelProcessingFilter * ChannelProcessingFilter
* WebAsyncManagerIntegrationFilter * WebAsyncManagerIntegrationFilter
* SecurityContextPersistenceFilter * SecurityContextPersistenceFilter

View File

@ -3,6 +3,35 @@
HTTP session related functionality is handled by a combination of the `SessionManagementFilter` and the `SessionAuthenticationStrategy` interface, which the filter delegates to. HTTP session related functionality is handled by a combination of the `SessionManagementFilter` and the `SessionAuthenticationStrategy` interface, which the filter delegates to.
Typical usage includes session-fixation protection attack prevention, detection of session timeouts and restrictions on how many sessions an authenticated user may have open concurrently. Typical usage includes session-fixation protection attack prevention, detection of session timeouts and restrictions on how many sessions an authenticated user may have open concurrently.
[[session-mgmt-force-session-creation]]
== Force Eager Session Creation
At times it can be valuable to eagerly create sessions.
This can be done by using the {security-api-url}org/springframework/security/web/session/ForceEagerSessionCreationFilter.html[`ForceEagerSessionCreationFilter`] which can be configured using:
====
.Java
[source,java,role="primary"]
----
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
http
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
);
return http.build();
}
----
.XML
[source,xml,role="secondary"]
----
<http create-session="ALWAYS">
</http>
----
====
== Detecting Timeouts == Detecting Timeouts
You can configure Spring Security to detect the submission of an invalid session ID and redirect the user to an appropriate URL. You can configure Spring Security to detect the submission of an invalid session ID and redirect the user to an appropriate URL.
This is achieved through the `session-management` element: This is achieved through the `session-management` element:

View File

@ -257,6 +257,10 @@ The filters are listed in the order in which they occur in the filter chain.
| `DisableEncodeUrlFilter` | `DisableEncodeUrlFilter`
| `http@disable-url-rewriting` | `http@disable-url-rewriting`
| FORCE_EAGER_SESSION_FILTER
| `ForceEagerSessionCreationFilter`
| `http@create-session="ALWAYS"`
| CHANNEL_FILTER | CHANNEL_FILTER
| `ChannelProcessingFilter` | `ChannelProcessingFilter`
| `http/intercept-url@requires-channel` | `http/intercept-url@requires-channel`

View File

@ -0,0 +1,48 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.session;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.core.log.LogMessage;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Eagerly creates {@link HttpSession} if it does not already exist.
*
* @author Rob Winch
* @since 5.7
*/
public class ForceEagerSessionCreationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpSession session = request.getSession();
if (this.logger.isDebugEnabled() && session.isNew()) {
this.logger.debug(LogMessage.format("Created session eagerly"));
}
filterChain.doFilter(request, response);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.session;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
class ForceEagerSessionCreationFilterTests {
@Test
void createsSession() throws Exception {
ForceEagerSessionCreationFilter filter = new ForceEagerSessionCreationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockFilterChain chain = new MockFilterChain();
filter.doFilter(request, new MockHttpServletResponse(), chain);
assertThat(request.getSession(false)).isNotNull();
assertThat(chain.getRequest()).isEqualTo(request);
}
}