Skip to content

Commit aaf7833

Browse files
committed
ForceEagerSessionCreationFilter
Closes gh-11109
1 parent 7fea639 commit aaf7833

File tree

14 files changed

+181
-31
lines changed

14 files changed

+181
-31
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
4444
import org.springframework.security.web.session.ConcurrentSessionFilter;
4545
import org.springframework.security.web.session.DisableEncodeUrlFilter;
46+
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
4647
import org.springframework.security.web.session.SessionManagementFilter;
4748

4849
/**
@@ -125,6 +126,7 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
125126
* The ordering of the Filters is:
126127
*
127128
* <ul>
129+
* <li>{@link ForceEagerSessionCreationFilter}</li>
128130
* <li>{@link DisableEncodeUrlFilter}</li>
129131
* <li>{@link ChannelProcessingFilter}</li>
130132
* <li>{@link SecurityContextPersistenceFilter}</li>

config/src/main/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
4848
import org.springframework.security.web.session.ConcurrentSessionFilter;
4949
import org.springframework.security.web.session.DisableEncodeUrlFilter;
50+
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
5051
import org.springframework.security.web.session.SessionManagementFilter;
5152
import org.springframework.web.filter.CorsFilter;
5253

@@ -70,6 +71,7 @@ final class FilterOrderRegistration {
7071
FilterOrderRegistration() {
7172
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
7273
put(DisableEncodeUrlFilter.class, order.next());
74+
put(ForceEagerSessionCreationFilter.class, order.next());
7375
put(ChannelProcessingFilter.class, order.next());
7476
order.next(); // gh-8105
7577
put(WebAsyncManagerIntegrationFilter.class, order.next());

config/src/main/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.security.web.context.SecurityContextHolderFilter;
2626
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
2727
import org.springframework.security.web.context.SecurityContextRepository;
28+
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
2829

2930
/**
3031
* Allows persisting and restoring of the {@link SecurityContext} found on the
@@ -117,6 +118,7 @@ public void configure(H http) {
117118
? sessionManagement.getSessionCreationPolicy() : null;
118119
if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
119120
securityContextFilter.setForceEagerSessionCreation(true);
121+
http.addFilter(postProcess(new ForceEagerSessionCreationFilter()));
120122
}
121123
securityContextFilter = postProcess(securityContextFilter);
122124
http.addFilter(securityContextFilter);

config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.springframework.security.web.savedrequest.RequestCache;
5454
import org.springframework.security.web.session.ConcurrentSessionFilter;
5555
import org.springframework.security.web.session.DisableEncodeUrlFilter;
56+
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
5657
import org.springframework.security.web.session.InvalidSessionStrategy;
5758
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
5859
import org.springframework.security.web.session.SessionManagementFilter;
@@ -380,6 +381,9 @@ public void configure(H http) {
380381
if (!this.enableSessionUrlRewriting) {
381382
http.addFilter(new DisableEncodeUrlFilter());
382383
}
384+
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
385+
http.addFilter(new ForceEagerSessionCreationFilter());
386+
}
383387
}
384388

385389
private ConcurrentSessionFilter createConcurrencyFilter(H http) {

config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
7070
import org.springframework.security.web.session.ConcurrentSessionFilter;
7171
import org.springframework.security.web.session.DisableEncodeUrlFilter;
72+
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
7273
import org.springframework.security.web.session.SessionManagementFilter;
7374
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
7475
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy;
@@ -148,6 +149,8 @@ class HttpConfigurationBuilder {
148149

149150
private BeanDefinition securityContextPersistenceFilter;
150151

152+
private BeanDefinition forceEagerSessionCreationFilter;
153+
151154
private BeanReference contextRepoRef;
152155

153156
private BeanReference sessionRegistryRef;
@@ -207,6 +210,7 @@ class HttpConfigurationBuilder {
207210
String createSession = element.getAttribute(ATT_CREATE_SESSION);
208211
this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED
209212
: createPolicy(createSession);
213+
createForceEagerSessionCreationFilter();
210214
createDisableEncodeUrlFilter();
211215
createCsrfFilter();
212216
createSecurityPersistence();
@@ -304,6 +308,12 @@ private boolean isExplicitSave() {
304308
return Boolean.parseBoolean(explicitSaveAttr);
305309
}
306310

311+
private void createForceEagerSessionCreationFilter() {
312+
if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
313+
this.forceEagerSessionCreationFilter = new RootBeanDefinition(ForceEagerSessionCreationFilter.class);
314+
}
315+
}
316+
307317
private void createSecurityContextPersistenceFilter() {
308318
BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class);
309319
switch (this.sessionPolicy) {
@@ -768,6 +778,10 @@ BeanReference getRequestCache() {
768778

769779
List<OrderDecorator> getFilters() {
770780
List<OrderDecorator> filters = new ArrayList<>();
781+
if (this.forceEagerSessionCreationFilter != null) {
782+
filters.add(new OrderDecorator(this.forceEagerSessionCreationFilter,
783+
SecurityFilters.FORCE_EAGER_SESSION_FILTER));
784+
}
771785
if (this.disableUrlRewriteFilter != null) {
772786
filters.add(new OrderDecorator(this.disableUrlRewriteFilter, SecurityFilters.DISABLE_ENCODE_URL_FILTER));
773787
}

config/src/main/java/org/springframework/security/config/http/SecurityFilters.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ enum SecurityFilters {
3131

3232
DISABLE_ENCODE_URL_FILTER,
3333

34+
FORCE_EAGER_SESSION_FILTER,
35+
3436
CHANNEL_FILTER,
3537

3638
SECURITY_CONTEXT_FILTER,

config/src/main/resources/org/springframework/security/config/spring-security-5.7.rnc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1318,4 +1318,4 @@ position =
13181318
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
13191319
attribute position {named-security-filter}
13201320

1321-
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"
1321+
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"

config/src/main/resources/org/springframework/security/config/spring-security-5.7.xsd

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@
124124
</xs:annotation>
125125
<xs:complexType/>
126126
</xs:element>
127-
127+
128128
<xs:attributeGroup name="password-encoder.attlist">
129129
<xs:attribute name="ref" type="xs:token">
130130
<xs:annotation>
@@ -408,7 +408,7 @@
408408
</xs:annotation>
409409
</xs:attribute>
410410
</xs:attributeGroup>
411-
411+
412412
<xs:attributeGroup name="ldap-ap.attlist">
413413
<xs:attribute name="server-ref" type="xs:token">
414414
<xs:annotation>
@@ -488,7 +488,7 @@
488488
</xs:annotation>
489489
</xs:attribute>
490490
</xs:attributeGroup>
491-
491+
492492
<xs:attributeGroup name="password-compare.attlist">
493493
<xs:attribute name="password-attribute" type="xs:token">
494494
<xs:annotation>
@@ -541,7 +541,7 @@
541541
</xs:annotation>
542542
</xs:attribute>
543543
</xs:attributeGroup>
544-
544+
545545
<xs:attributeGroup name="protect.attlist">
546546
<xs:attribute name="method" use="required" type="xs:token">
547547
<xs:annotation>
@@ -842,13 +842,13 @@
842842
</xs:annotation>
843843
</xs:attribute>
844844
</xs:attributeGroup>
845-
846-
847-
848-
849-
850-
851-
845+
846+
847+
848+
849+
850+
851+
852852
<xs:attributeGroup name="protect-pointcut.attlist">
853853
<xs:attribute name="expression" use="required" type="xs:string">
854854
<xs:annotation>
@@ -1323,7 +1323,7 @@
13231323
</xs:annotation>
13241324
</xs:attribute>
13251325
</xs:attributeGroup>
1326-
1326+
13271327
<xs:attributeGroup name="access-denied-handler.attlist">
13281328
<xs:attribute name="ref" type="xs:token">
13291329
<xs:annotation>
@@ -1348,7 +1348,7 @@
13481348
</xs:annotation>
13491349
</xs:attribute>
13501350
</xs:attributeGroup>
1351-
1351+
13521352
<xs:attributeGroup name="intercept-url.attlist">
13531353
<xs:attribute name="pattern" type="xs:token">
13541354
<xs:annotation>
@@ -1405,7 +1405,7 @@
14051405
</xs:annotation>
14061406
</xs:attribute>
14071407
</xs:attributeGroup>
1408-
1408+
14091409
<xs:attributeGroup name="logout.attlist">
14101410
<xs:attribute name="logout-url" type="xs:token">
14111411
<xs:annotation>
@@ -1452,7 +1452,7 @@
14521452
<xs:attributeGroup ref="security:ref"/>
14531453
</xs:complexType>
14541454
</xs:element>
1455-
1455+
14561456
<xs:attributeGroup name="form-login.attlist">
14571457
<xs:attribute name="login-processing-url" type="xs:token">
14581458
<xs:annotation>
@@ -1967,7 +1967,7 @@
19671967
</xs:annotation>
19681968
</xs:attribute>
19691969
</xs:attributeGroup>
1970-
1970+
19711971
<xs:element name="attribute-exchange">
19721972
<xs:annotation>
19731973
<xs:documentation>Sets up an attribute exchange configuration to request specified attributes from the
@@ -2034,7 +2034,7 @@
20342034
</xs:annotation>
20352035
</xs:attribute>
20362036
</xs:attributeGroup>
2037-
2037+
20382038
<xs:attributeGroup name="saml2-login.attlist">
20392039
<xs:attribute name="relying-party-registration-repository-ref" type="xs:token">
20402040
<xs:annotation>
@@ -2091,7 +2091,7 @@
20912091
</xs:annotation>
20922092
</xs:attribute>
20932093
</xs:attributeGroup>
2094-
2094+
20952095
<xs:attributeGroup name="saml2-logout.attlist">
20962096
<xs:attribute name="logout-url" type="xs:token">
20972097
<xs:annotation>
@@ -2544,7 +2544,7 @@
25442544
</xs:simpleType>
25452545
</xs:attribute>
25462546
</xs:attributeGroup>
2547-
2547+
25482548
<xs:attributeGroup name="http-basic.attlist">
25492549
<xs:attribute name="entry-point-ref" type="xs:token">
25502550
<xs:annotation>
@@ -2577,7 +2577,7 @@
25772577
</xs:annotation>
25782578
</xs:attribute>
25792579
</xs:attributeGroup>
2580-
2580+
25812581
<xs:attributeGroup name="session-management.attlist">
25822582
<xs:attribute name="session-fixation-protection">
25832583
<xs:annotation>
@@ -2633,7 +2633,7 @@
26332633
</xs:annotation>
26342634
</xs:attribute>
26352635
</xs:attributeGroup>
2636-
2636+
26372637
<xs:attributeGroup name="concurrency-control.attlist">
26382638
<xs:attribute name="max-sessions" type="xs:token">
26392639
<xs:annotation>
@@ -2680,7 +2680,7 @@
26802680
</xs:annotation>
26812681
</xs:attribute>
26822682
</xs:attributeGroup>
2683-
2683+
26842684
<xs:attributeGroup name="remember-me.attlist">
26852685
<xs:attribute name="key" type="xs:token">
26862686
<xs:annotation>
@@ -2778,7 +2778,7 @@
27782778
<xs:attributeGroup name="remember-me-data-source-ref">
27792779
<xs:attributeGroup ref="security:data-source-ref"/>
27802780
</xs:attributeGroup>
2781-
2781+
27822782
<xs:attributeGroup name="anonymous.attlist">
27832783
<xs:attribute name="key" type="xs:token">
27842784
<xs:annotation>
@@ -2811,8 +2811,8 @@
28112811
</xs:annotation>
28122812
</xs:attribute>
28132813
</xs:attributeGroup>
2814-
2815-
2814+
2815+
28162816
<xs:attributeGroup name="http-port">
28172817
<xs:attribute name="http" use="required" type="xs:token">
28182818
<xs:annotation>
@@ -2829,7 +2829,7 @@
28292829
</xs:annotation>
28302830
</xs:attribute>
28312831
</xs:attributeGroup>
2832-
2832+
28332833
<xs:attributeGroup name="x509.attlist">
28342834
<xs:attribute name="subject-principal-regex" type="xs:token">
28352835
<xs:annotation>
@@ -2966,7 +2966,7 @@
29662966
</xs:annotation>
29672967
</xs:attribute>
29682968
</xs:attributeGroup>
2969-
2969+
29702970
<xs:attributeGroup name="ap.attlist">
29712971
<xs:attribute name="ref" type="xs:token">
29722972
<xs:annotation>
@@ -3018,7 +3018,7 @@
30183018
</xs:annotation>
30193019
</xs:attribute>
30203020
</xs:attributeGroup>
3021-
3021+
30223022
<xs:attributeGroup name="user.attlist">
30233023
<xs:attribute name="name" use="required" type="xs:token">
30243024
<xs:annotation>
@@ -3721,6 +3721,7 @@
37213721
<xs:restriction base="xs:token">
37223722
<xs:enumeration value="FIRST"/>
37233723
<xs:enumeration value="DISABLE_ENCODE_URL_FILTER"/>
3724+
<xs:enumeration value="FORCE_EAGER_SESSION_FILTER"/>
37243725
<xs:enumeration value="CHANNEL_FILTER"/>
37253726
<xs:enumeration value="SECURITY_CONTEXT_FILTER"/>
37263727
<xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
@@ -3760,4 +3761,4 @@
37603761
<xs:enumeration value="LAST"/>
37613762
</xs:restriction>
37623763
</xs:simpleType>
3763-
</xs:schema>
3764+
</xs:schema>

config/src/test/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistrationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public void putWhenCustomFilterAlreadyExistsThenDoesNotOverride() {
5353

5454
@Test
5555
public void putWhenPredefinedFilterThenDoesNotOverride() {
56-
int position = 200;
56+
int position = 300;
5757
Integer predefinedFilterOrderBefore = this.filterOrderRegistration.getOrder(ChannelProcessingFilter.class);
5858
this.filterOrderRegistration.put(MyFilter.class, position);
5959
Integer myFilterOrder = this.filterOrderRegistration.getOrder(MyFilter.class);

docs/modules/ROOT/pages/servlet/architecture.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ However, there are times that it is beneficial to know the ordering
165165

166166
Below is a comprehensive list of Spring Security Filter ordering:
167167

168+
* xref:servlet/authentication/session-management.adoc#session-mgmt-force-session-creation[`ForceEagerSessionCreationFilter`]
168169
* ChannelProcessingFilter
169170
* WebAsyncManagerIntegrationFilter
170171
* SecurityContextPersistenceFilter

0 commit comments

Comments
 (0)