From 89f8310d6c90baf65fe97896541ede132e988a49 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Wed, 17 Aug 2022 15:20:07 -0500 Subject: [PATCH] Add Explicit SessionAuthenticationStrategy Option SessionAuthenticationFilter requires accessing the HttpSession to do its job. Previously, there was no way to just disable the SessionAuthenticationFilter despite the fact that SessionAuthenticationStrategy is invoked by the authentication filters directly. This commit adds an option to disable SessionManagmentFilter in favor of requiring explicit SessionAuthenticationStrategy invocation already performed by the authentication filters. Closes gh-11455 --- .../SessionManagementConfigurer.java | 52 ++++++++++++++----- .../config/http/HttpConfigurationBuilder.java | 8 ++- .../security/config/spring-security-5.8.rnc | 3 ++ .../security/config/spring-security-5.8.xsd | 7 +++ .../servlet/appendix/namespace/http.adoc | 4 ++ 5 files changed, 59 insertions(+), 15 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java index 4f394a59d5..27f37f786e 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java @@ -135,6 +135,8 @@ public final class SessionManagementConfigurer> private AuthenticationFailureHandler sessionAuthenticationFailureHandler; + private boolean requireExplicitAuthenticationStrategy; + /** * Creates a new instance * @see HttpSecurity#sessionManagement() @@ -155,6 +157,19 @@ public final class SessionManagementConfigurer> return this; } + /** + * Setting this means that explicit invocation of + * {@link SessionAuthenticationStrategy} is required. + * @param requireExplicitAuthenticationStrategy require explicit invocation of + * {@link SessionAuthenticationStrategy} + * @return the {@link SessionManagementConfigurer} for further customization + */ + public SessionManagementConfigurer requireExplicitAuthenticationStrategy( + boolean requireExplicitAuthenticationStrategy) { + this.requireExplicitAuthenticationStrategy = requireExplicitAuthenticationStrategy; + return this; + } + /** * Setting this attribute will inject the provided invalidSessionStrategy into the * {@link SessionManagementFilter}. When an invalid session ID is submitted, the @@ -351,6 +366,28 @@ public final class SessionManagementConfigurer> @Override public void configure(H http) { + SessionManagementFilter sessionManagementFilter = createSessionManagementFilter(http); + if (sessionManagementFilter != null) { + http.addFilter(sessionManagementFilter); + } + if (isConcurrentSessionControlEnabled()) { + ConcurrentSessionFilter concurrentSessionFilter = createConcurrencyFilter(http); + + concurrentSessionFilter = postProcess(concurrentSessionFilter); + http.addFilter(concurrentSessionFilter); + } + if (!this.enableSessionUrlRewriting) { + http.addFilter(new DisableEncodeUrlFilter()); + } + if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) { + http.addFilter(new ForceEagerSessionCreationFilter()); + } + } + + private SessionManagementFilter createSessionManagementFilter(H http) { + if (this.requireExplicitAuthenticationStrategy) { + return null; + } SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class); SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository, getSessionAuthenticationStrategy(http)); @@ -371,20 +408,7 @@ public final class SessionManagementConfigurer> sessionManagementFilter.setTrustResolver(trustResolver); } sessionManagementFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy()); - sessionManagementFilter = postProcess(sessionManagementFilter); - http.addFilter(sessionManagementFilter); - if (isConcurrentSessionControlEnabled()) { - ConcurrentSessionFilter concurrentSessionFilter = createConcurrencyFilter(http); - - concurrentSessionFilter = postProcess(concurrentSessionFilter); - http.addFilter(concurrentSessionFilter); - } - if (!this.enableSessionUrlRewriting) { - http.addFilter(new DisableEncodeUrlFilter()); - } - if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) { - http.addFilter(new ForceEagerSessionCreationFilter()); - } + return postProcess(sessionManagementFilter); } private ConcurrentSessionFilter createConcurrencyFilter(H http) { 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 940eba4cf5..9bc23955bb 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 @@ -103,6 +103,8 @@ class HttpConfigurationBuilder { private static final String OPT_CHANGE_SESSION_ID = "changeSessionId"; + private static final String ATT_AUTHENTICATION_STRATEGY_EXPLICIT_INVOCATION = "authentication-strategy-explicit-invocation"; + private static final String ATT_INVALID_SESSION_URL = "invalid-session-url"; private static final String ATT_SESSION_AUTH_STRATEGY_REF = "session-authentication-strategy-ref"; @@ -538,7 +540,11 @@ class HttpConfigurationBuilder { sessionMgmtFilter.addPropertyReference("invalidSessionStrategy", invalidSessionStrategyRef); } sessionMgmtFilter.addConstructorArgReference(sessionAuthStratRef); - this.sfpf = (RootBeanDefinition) sessionMgmtFilter.getBeanDefinition(); + boolean registerSessionMgmtFilter = (sessionMgmtElt == null + || !"true".equals(sessionMgmtElt.getAttribute(ATT_AUTHENTICATION_STRATEGY_EXPLICIT_INVOCATION))); + if (registerSessionMgmtFilter) { + this.sfpf = (RootBeanDefinition) sessionMgmtFilter.getBeanDefinition(); + } this.sessionStrategyRef = new RuntimeBeanReference(sessionAuthStratRef); } diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-5.8.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-5.8.rnc index 6104ee7cc5..99d750d80f 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-5.8.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-5.8.rnc @@ -917,6 +917,9 @@ session-management = ## Session-management related functionality is implemented by the addition of a SessionManagementFilter to the filter stack. element session-management {session-management.attlist, concurrency-control?} +session-management.attlist &= + ## Specifies that SessionAuthenticationStrategy must be explicitly invoked. Default false (i.e. SessionManagementFilter will implicitly invoke SessionAuthenticationStrategy). + attribute authentication-strategy-explicit-invocation {xsd:boolean}? session-management.attlist &= ## Indicates how session fixation protection will be applied when a user authenticates. If set to "none", no protection will be applied. "newSession" will create a new empty session, with only Spring Security-related attributes migrated. "migrateSession" will create a new session and copy all session attributes to the new session. In Servlet 3.1 (Java EE 7) and newer containers, specifying "changeSessionId" will keep the existing session and use the container-supplied session fixation protection (HttpServletRequest#changeSessionId()). Defaults to "changeSessionId" in Servlet 3.1 and newer containers, "migrateSession" in older containers. Throws an exception if "changeSessionId" is used in older containers. attribute session-fixation-protection {"none" | "newSession" | "migrateSession" | "changeSessionId" }? diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-5.8.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-5.8.xsd index 4255a1ae11..330518a666 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-5.8.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-5.8.xsd @@ -2662,6 +2662,13 @@ + + + Specifies that SessionAuthenticationStrategy must be explicitly invoked. Default false + (i.e. SessionManagementFilter will implicitly invoke SessionAuthenticationStrategy). + + + Indicates how session fixation protection will be applied when a user authenticates. If diff --git a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc index 1bd4b70907..0253607b31 100644 --- a/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc +++ b/docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc @@ -2243,6 +2243,10 @@ Session-management related functionality is implemented by the addition of a `Se === Attributes +[[nsa-session-management-authentication-strategy-explicit-invocation]] +* **authentication-strategy-explicit-invocation** +Setting this attribute to true will mean that `SessionManagementFilter` will not be injected and explicit invocation of SessionAuthenticationStrategy is required. + [[nsa-session-management-invalid-session-url]] * **invalid-session-url** Setting this attribute will inject the `SessionManagementFilter` with a `SimpleRedirectInvalidSessionStrategy` configured with the attribute value.