Browse Source

ForceEagerSessionCreationFilter

Closes gh-11109
Rob Winch 3 năm trước cách đây
mục cha
commit
aaf78330b1

+ 2 - 0
config/src/main/java/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java

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

+ 2 - 0
config/src/main/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistration.java

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

+ 2 - 0
config/src/main/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurer.java

@@ -25,6 +25,7 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
 import org.springframework.security.web.context.SecurityContextHolderFilter;
 import org.springframework.security.web.context.SecurityContextPersistenceFilter;
 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
@@ -117,6 +118,7 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
 					? sessionManagement.getSessionCreationPolicy() : null;
 			if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
 				securityContextFilter.setForceEagerSessionCreation(true);
+				http.addFilter(postProcess(new ForceEagerSessionCreationFilter()));
 			}
 			securityContextFilter = postProcess(securityContextFilter);
 			http.addFilter(securityContextFilter);

+ 4 - 0
config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java

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

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

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

+ 2 - 0
config/src/main/java/org/springframework/security/config/http/SecurityFilters.java

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

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

@@ -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.
 	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"

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

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

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

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

+ 1 - 0
docs/modules/ROOT/pages/servlet/architecture.adoc

@@ -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:
 
+* xref:servlet/authentication/session-management.adoc#session-mgmt-force-session-creation[`ForceEagerSessionCreationFilter`]
 * ChannelProcessingFilter
 * WebAsyncManagerIntegrationFilter
 * SecurityContextPersistenceFilter

+ 29 - 0
docs/modules/ROOT/pages/servlet/authentication/session-management.adoc

@@ -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.
 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
 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:

+ 4 - 0
docs/modules/ROOT/pages/servlet/configuration/xml-namespace.adoc

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

+ 48 - 0
web/src/main/java/org/springframework/security/web/session/ForceEagerSessionCreationFilter.java

@@ -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);
+	}
+
+}

+ 41 - 0
web/src/test/java/org/springframework/security/web/session/ForceEagerSessionCreationFilterTests.java

@@ -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);
+	}
+
+}