getJWKSource() {
+ OctetSequenceKey key = new OctetSequenceKey.Builder(
+ secretKey).algorithm(getAlgorithm()).build();
+ JWKSet jwkSet = new JWKSet(key);
+ return (jwkSelector, context) -> jwkSelector.select(jwkSet);
+ }
+
+ JWSAlgorithm getAlgorithm() {
+ return JWSAlgorithm.parse(jwsAlgorithm.getName());
+ }
+ }
+}
diff --git a/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/VaadinWebSecurityConfigurerAdapter.java b/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/VaadinWebSecurityConfigurerAdapter.java
index 2f01684b0..4ec6f2d72 100644
--- a/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/VaadinWebSecurityConfigurerAdapter.java
+++ b/vaadin-spring/src/main/java/com/vaadin/flow/spring/security/VaadinWebSecurityConfigurerAdapter.java
@@ -15,17 +15,11 @@
*/
package com.vaadin.flow.spring.security;
+import javax.crypto.SecretKey;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import com.vaadin.flow.component.Component;
-import com.vaadin.flow.internal.AnnotationReader;
-import com.vaadin.flow.router.Route;
-import com.vaadin.flow.router.internal.RouteUtil;
-import com.vaadin.flow.server.HandlerHelper;
-import com.vaadin.flow.server.auth.ViewAccessChecker;
-
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
@@ -33,10 +27,19 @@
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
+import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
+import com.vaadin.flow.component.Component;
+import com.vaadin.flow.internal.AnnotationReader;
+import com.vaadin.flow.router.Route;
+import com.vaadin.flow.router.internal.RouteUtil;
+import com.vaadin.flow.server.HandlerHelper;
+import com.vaadin.flow.server.auth.ViewAccessChecker;
+
/**
* Provides basic Vaadin security configuration for the project.
*
@@ -55,10 +58,9 @@
@EnableWebSecurity
@Configuration
public class MySecurityConfigurerAdapter extends VaadinWebSecurityConfigurerAdapter {
-
-}
+
+}
*
- *
*/
public abstract class VaadinWebSecurityConfigurerAdapter
extends WebSecurityConfigurerAdapter {
@@ -157,7 +159,7 @@ public static RequestMatcher getDefaultWebSecurityIgnoreMatcher() {
*
* This is used when your application uses a Fusion based login view
* available at the given path.
- *
+ *
* @param http
* the http security from {@link #configure(HttpSecurity)}
* @param fusionLoginViewPath
@@ -176,7 +178,7 @@ protected void setLoginView(HttpSecurity http, String fusionLoginViewPath)
*
* This is used when your application uses a Fusion based login view
* available at the given path.
- *
+ *
* @param http
* the http security from {@link #configure(HttpSecurity)}
* @param fusionLoginViewPath
@@ -191,14 +193,14 @@ protected void setLoginView(HttpSecurity http, String fusionLoginViewPath,
FormLoginConfigurer formLogin = http.formLogin();
formLogin.loginPage(fusionLoginViewPath).permitAll();
formLogin.successHandler(
- new VaadinSavedRequestAwareAuthenticationSuccessHandler());
+ getVaadinSavedRequestAwareAuthenticationSuccessHandler(http));
http.logout().logoutSuccessUrl(logoutUrl);
viewAccessChecker.setLoginView(fusionLoginViewPath);
}
/**
* Sets up login for the application using the given Flow login view.
- *
+ *
* @param http
* the http security from {@link #configure(HttpSecurity)}
* @param flowLoginView
@@ -213,14 +215,14 @@ protected void setLoginView(HttpSecurity http,
/**
* Sets up login for the application using the given Flow login view.
- *
+ *
* @param http
* the http security from {@link #configure(HttpSecurity)}
* @param flowLoginView
* the login view to use
* @param logoutUrl
* the URL to redirect the user to after logging out
- *
+ *
* @throws Exception
* if something goes wrong
*/
@@ -245,10 +247,63 @@ protected void setLoginView(HttpSecurity http,
FormLoginConfigurer formLogin = http.formLogin();
formLogin.loginPage(loginPath).permitAll();
formLogin.successHandler(
- new VaadinSavedRequestAwareAuthenticationSuccessHandler());
+ getVaadinSavedRequestAwareAuthenticationSuccessHandler(http));
http.csrf().ignoringAntMatchers(loginPath);
http.logout().logoutSuccessUrl(logoutUrl);
viewAccessChecker.setLoginView(flowLoginView);
}
+ /**
+ * Sets up stateless JWT authentication using cookies.
+ *
+ * @param http
+ * the http security from {@link #configure(HttpSecurity)}
+ * @param secretKey
+ * the secret key for encoding and decoding JWTs, must use a
+ * {@link MacAlgorithm} algorithm name
+ * @param issuer
+ * the issuer JWT claim
+ * @throws Exception
+ * if something goes wrong
+ */
+ protected void setStatelessAuthentication(HttpSecurity http,
+ SecretKey secretKey, String issuer) throws Exception {
+ setStatelessAuthentication(http, secretKey, issuer, 1800L);
+ }
+
+ /**
+ * Sets up stateless JWT authentication using cookies.
+ *
+ * @param http
+ * the http security from {@link #configure(HttpSecurity)}
+ * @param secretKey
+ * the secret key for encoding and decoding JWTs, must use a
+ * {@link MacAlgorithm} algorithm name
+ * @param issuer
+ * the issuer JWT claim
+ * @param expiresIn
+ * lifetime of the JWT and cookies, in seconds
+ * @throws Exception
+ * if something goes wrong
+ */
+ protected void setStatelessAuthentication(HttpSecurity http,
+ SecretKey secretKey, String issuer, long expiresIn)
+ throws Exception {
+ VaadinStatelessSecurityConfigurer vaadinStatelessSecurityConfigurer = new VaadinStatelessSecurityConfigurer<>();
+ http.apply(vaadinStatelessSecurityConfigurer);
+
+ vaadinStatelessSecurityConfigurer.withSecretKey().secretKey(secretKey)
+ .and().issuer(issuer).expiresIn(expiresIn);
+ }
+
+ private VaadinSavedRequestAwareAuthenticationSuccessHandler getVaadinSavedRequestAwareAuthenticationSuccessHandler(
+ HttpSecurity http) {
+ VaadinSavedRequestAwareAuthenticationSuccessHandler vaadinSavedRequestAwareAuthenticationSuccessHandler = new VaadinSavedRequestAwareAuthenticationSuccessHandler();
+ RequestCache requestCache = http.getSharedObject(RequestCache.class);
+ if (requestCache != null) {
+ vaadinSavedRequestAwareAuthenticationSuccessHandler.setRequestCache(
+ requestCache);
+ }
+ return vaadinSavedRequestAwareAuthenticationSuccessHandler;
+ }
}
diff --git a/vaadin-spring/src/test/java/com/vaadin/flow/spring/SpringClassesSerializableTest.java b/vaadin-spring/src/test/java/com/vaadin/flow/spring/SpringClassesSerializableTest.java
index bae363d28..499ee013d 100644
--- a/vaadin-spring/src/test/java/com/vaadin/flow/spring/SpringClassesSerializableTest.java
+++ b/vaadin-spring/src/test/java/com/vaadin/flow/spring/SpringClassesSerializableTest.java
@@ -88,11 +88,17 @@ protected Stream getExcludedPatterns() {
"com\\.vaadin\\.flow\\.spring\\.scopes\\.VaadinSessionScope",
"com\\.vaadin\\.flow\\.spring\\.scopes\\.AbstractScope",
"com\\.vaadin\\.flow\\.spring\\.scopes\\.VaadinUIScope",
+ "com\\.vaadin\\.flow\\.spring\\.security\\.JwtSecurityContextRepository",
+ "com\\.vaadin\\.flow\\.spring\\.security\\.JwtSecurityContextRepository\\$UpdateJwtResponseWrapper",
+ "com\\.vaadin\\.flow\\.spring\\.security\\.SerializedJwtSplitCookieRepository",
"com\\.vaadin\\.flow\\.spring\\.security\\.VaadinAwareSecurityContextHolderStrategy",
"com\\.vaadin\\.flow\\.spring\\.security\\.VaadinWebSecurityConfigurerAdapter",
"com\\.vaadin\\.flow\\.spring\\.security\\.VaadinDefaultRequestCache",
"com\\.vaadin\\.flow\\.spring\\.security\\.VaadinSavedRequestAwareAuthenticationSuccessHandler",
"com\\.vaadin\\.flow\\.spring\\.security\\.VaadinSavedRequestAwareAuthenticationSuccessHandler\\$RedirectStrategy",
+ "com\\.vaadin\\.flow\\.spring\\.security\\.VaadinStatelessSecurityConfigurer",
+ "com\\.vaadin\\.flow\\.spring\\.security\\.VaadinStatelessSecurityConfigurer\\$SecretKeyConfigurer",
+ "com\\.vaadin\\.flow\\.spring\\.security\\.VaadinWebSecurityConfigurerAdapter\\$BearerTokenAuthentiationFilterPostProcessor",
"com\\.vaadin\\.flow\\.spring\\.VaadinServletContextInitializer\\$ClassPathScanner",
"com\\.vaadin\\.flow\\.spring\\.VaadinServletContextInitializer\\$CustomResourceLoader"),
super.getExcludedPatterns());
diff --git a/vaadin-spring/src/test/java/com/vaadin/flow/spring/security/SerializedJwtSplitCookieRepositoryTest.java b/vaadin-spring/src/test/java/com/vaadin/flow/spring/security/SerializedJwtSplitCookieRepositoryTest.java
new file mode 100644
index 000000000..30cc2aeab
--- /dev/null
+++ b/vaadin-spring/src/test/java/com/vaadin/flow/spring/security/SerializedJwtSplitCookieRepositoryTest.java
@@ -0,0 +1,222 @@
+package com.vaadin.flow.spring.security;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class SerializedJwtSplitCookieRepositoryTest {
+ private static final int DEFAULT_MAX_AGE = 1800;
+ private static final int CUSTOM_MAX_AGE = 3600;
+ private static final String JWT_HEADER_AND_PAYLOAD = "foo.bar";
+ private static final String JWT_SIGNATURE = "baz";
+ private static final String JWT =
+ JWT_HEADER_AND_PAYLOAD + "." + JWT_SIGNATURE;
+ private static final String JWT_SIGNATURE_NAME = "jwt.signature";
+ private static final String JWT_HEADER_AND_PAYLOAD_NAME = "jwt.headerAndPayload";
+ private static final Cookie JWT_HEADER_AND_PAYLOAD_COOKIE;
+ private static final Cookie JWT_SIGNATURE_COOKIE;
+ private static final String CONTEXT_PATH = "/context-path/";
+
+ static {
+ JWT_HEADER_AND_PAYLOAD_COOKIE = new Cookie(JWT_HEADER_AND_PAYLOAD_NAME,
+ JWT_HEADER_AND_PAYLOAD);
+ JWT_SIGNATURE_COOKIE = new Cookie(JWT_SIGNATURE_NAME, JWT_SIGNATURE);
+ }
+
+ private SerializedJwtSplitCookieRepository serializedJwtSplitCookieRepository;
+ private HttpServletRequest request;
+ private HttpServletResponse response;
+
+ @Before
+ public void setup() {
+ serializedJwtSplitCookieRepository = new SerializedJwtSplitCookieRepository();
+ request = Mockito.mock(HttpServletRequest.class);
+ Mockito.doReturn(CONTEXT_PATH).when(request).getContextPath();
+ Mockito.doReturn(true).when(request).isSecure();
+ response = Mockito.mock(HttpServletResponse.class);
+ }
+
+ @Test
+ public void containsSerializedJwt_true_when_bothCookiesPreset() {
+ Mockito.doReturn(new Cookie[] { JWT_HEADER_AND_PAYLOAD_COOKIE,
+ JWT_SIGNATURE_COOKIE }).when(request).getCookies();
+ Assert.assertTrue(
+ serializedJwtSplitCookieRepository.containsSerializedJwt(
+ request));
+ }
+
+ @Test
+ public void containsSerializedJwt_false_when_signatureCookieMissing() {
+ Mockito.doReturn(new Cookie[] { JWT_HEADER_AND_PAYLOAD_COOKIE })
+ .when(request).getCookies();
+ Assert.assertFalse(
+ serializedJwtSplitCookieRepository.containsSerializedJwt(
+ request));
+ }
+
+ @Test
+ public void containsSerializedJwt_false_when_headerAndPayloadCookieMissing() {
+ Mockito.doReturn(new Cookie[] { JWT_SIGNATURE_COOKIE }).when(request)
+ .getCookies();
+ Assert.assertFalse(
+ serializedJwtSplitCookieRepository.containsSerializedJwt(
+ request));
+ }
+
+ @Test
+ public void containsSerializedJwt_false_when_bothCookiesMissing() {
+ Mockito.doReturn(new Cookie[] {}).when(request).getCookies();
+ Assert.assertFalse(
+ serializedJwtSplitCookieRepository.containsSerializedJwt(
+ request));
+ }
+
+ @Test
+ public void containsSerializedJwt_false_when_cookiesNull() {
+ Mockito.doReturn(null).when(request).getCookies();
+ Assert.assertFalse(
+ serializedJwtSplitCookieRepository.containsSerializedJwt(
+ request));
+ }
+
+ @Test
+ public void loadSerializedJwt_returnsString_when_cookiesPresent() {
+ Mockito.doReturn(new Cookie[] { JWT_HEADER_AND_PAYLOAD_COOKIE,
+ JWT_SIGNATURE_COOKIE }).when(request).getCookies();
+
+ String serializedJwt = serializedJwtSplitCookieRepository.loadSerializedJwt(
+ request);
+ Assert.assertEquals(JWT, serializedJwt);
+ }
+
+ @Test
+ public void loadSerializedJwt_returnsNull_when_headerAndPayloadCookieMissing() {
+ Mockito.doReturn(new Cookie[] { JWT_SIGNATURE_COOKIE }).when(request)
+ .getCookies();
+
+ String serializedJwt;
+ serializedJwt = serializedJwtSplitCookieRepository.loadSerializedJwt(
+ request);
+ Assert.assertNull(JWT, serializedJwt);
+ }
+
+ @Test
+ public void loadSerializedJwt_returnsNull_when_signatureCookieMissing() {
+ Mockito.doReturn(new Cookie[] { JWT_HEADER_AND_PAYLOAD_COOKIE })
+ .when(request).getCookies();
+
+ String serializedJwt;
+ serializedJwt = serializedJwtSplitCookieRepository.loadSerializedJwt(
+ request);
+ Assert.assertNull(JWT, serializedJwt);
+ }
+
+ @Test
+ public void loadSerializedJwt_returnsNull_when_bothCookiesMissing() {
+ Mockito.doReturn(new Cookie[] {}).when(request).getCookies();
+
+ String serializedJwt;
+ serializedJwt = serializedJwtSplitCookieRepository.loadSerializedJwt(
+ request);
+ Assert.assertNull(JWT, serializedJwt);
+ }
+
+
+ @Test
+ public void loadSerializedJwt_returnsNull_when_cookiesNull() {
+ Mockito.doReturn(null).when(request).getCookies();
+
+ String serializedJwt;
+ serializedJwt = serializedJwtSplitCookieRepository.loadSerializedJwt(
+ request);
+ Assert.assertNull(JWT, serializedJwt);
+ }
+
+ @Test
+ public void saveSerializedJwt_sets_cookiePair() {
+ serializedJwtSplitCookieRepository.saveSerializedJwt(JWT, request,
+ response);
+ checkResponseCookiePair(JWT_HEADER_AND_PAYLOAD, JWT_SIGNATURE, true,
+ DEFAULT_MAX_AGE - 1, CONTEXT_PATH);
+ }
+
+ @Test
+ public void saveSerializedJwt_resets_cookiePair() {
+ serializedJwtSplitCookieRepository.saveSerializedJwt(null, request,
+ response);
+ checkResponseCookiePair(null, null, true, 0, CONTEXT_PATH);
+ }
+
+ @Test
+ public void saveSerializedJwt_setsWithMaxAge_after_setExpireIn() {
+ serializedJwtSplitCookieRepository.setExpiresIn(CUSTOM_MAX_AGE);
+ serializedJwtSplitCookieRepository.saveSerializedJwt(JWT, request,
+ response);
+ checkResponseCookiePair(JWT_HEADER_AND_PAYLOAD, JWT_SIGNATURE, true,
+ CUSTOM_MAX_AGE - 1, CONTEXT_PATH);
+ }
+
+ @Test
+ public void saveSerializedJwt_resetsWithoutMaxAge_after_setExpireIn() {
+ serializedJwtSplitCookieRepository.setExpiresIn(CUSTOM_MAX_AGE);
+ serializedJwtSplitCookieRepository.saveSerializedJwt(null, request,
+ response);
+ checkResponseCookiePair(null, null, true, 0, CONTEXT_PATH);
+ }
+
+ @Test
+ public void saveSerializedJwt_sets_withNonSecure_request() {
+ Mockito.doReturn(false).when(request).isSecure();
+ serializedJwtSplitCookieRepository.saveSerializedJwt(JWT, request,
+ response);
+ checkResponseCookiePair(JWT_HEADER_AND_PAYLOAD, JWT_SIGNATURE, false,
+ DEFAULT_MAX_AGE - 1, CONTEXT_PATH);
+ }
+
+ @Test
+ public void saveSerializedJwt_sets_withEmptyContextPath() {
+ Mockito.doReturn("").when(request).getContextPath();
+ serializedJwtSplitCookieRepository.saveSerializedJwt(JWT, request,
+ response);
+ checkResponseCookiePair(JWT_HEADER_AND_PAYLOAD, JWT_SIGNATURE, true,
+ DEFAULT_MAX_AGE - 1, "/");
+ }
+
+ private void checkResponseCookiePair(String expectedHeaderAndPayload,
+ String expectedSignature, boolean expectedIsSecure, int maxAge,
+ String expectedPath) {
+ ArgumentCaptor cookieArgumentCaptor = ArgumentCaptor.forClass(
+ Cookie.class);
+ Mockito.verify(response, Mockito.times(2))
+ .addCookie(cookieArgumentCaptor.capture());
+ List cookieList = cookieArgumentCaptor.getAllValues();
+
+ Cookie headerAndPayloadCookie = cookieList.get(0);
+ Assert.assertNotNull(headerAndPayloadCookie);
+ Assert.assertEquals(JWT_HEADER_AND_PAYLOAD_NAME,
+ headerAndPayloadCookie.getName());
+ Assert.assertEquals(expectedHeaderAndPayload,
+ headerAndPayloadCookie.getValue());
+ Assert.assertFalse(headerAndPayloadCookie.isHttpOnly());
+ Assert.assertEquals(expectedIsSecure,
+ headerAndPayloadCookie.getSecure());
+ Assert.assertEquals(expectedPath, headerAndPayloadCookie.getPath());
+ Assert.assertEquals(maxAge, headerAndPayloadCookie.getMaxAge());
+
+ Cookie signatureCookie = cookieList.get(1);
+ Assert.assertNotNull(signatureCookie);
+ Assert.assertEquals(JWT_SIGNATURE_NAME, signatureCookie.getName());
+ Assert.assertEquals(expectedSignature, signatureCookie.getValue());
+ Assert.assertTrue(signatureCookie.isHttpOnly());
+ Assert.assertEquals(expectedIsSecure, signatureCookie.getSecure());
+ Assert.assertEquals(expectedPath, signatureCookie.getPath());
+ Assert.assertEquals(maxAge, signatureCookie.getMaxAge());
+ }
+}
\ No newline at end of file
diff --git a/vaadin-spring/src/test/java/com/vaadin/flow/spring/security/VaadinDefaultRequestCacheTest.java b/vaadin-spring/src/test/java/com/vaadin/flow/spring/security/VaadinDefaultRequestCacheTest.java
index 3b6a0f49d..4c0b25214 100644
--- a/vaadin-spring/src/test/java/com/vaadin/flow/spring/security/VaadinDefaultRequestCacheTest.java
+++ b/vaadin-spring/src/test/java/com/vaadin/flow/spring/security/VaadinDefaultRequestCacheTest.java
@@ -1,18 +1,9 @@
package com.vaadin.flow.spring.security;
-import java.lang.reflect.Method;
-import java.util.Collections;
-
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-
-import com.vaadin.flow.server.HandlerHelper.RequestType;
-import com.vaadin.fusion.Endpoint;
-import com.vaadin.fusion.EndpointRegistry;
-import com.vaadin.fusion.FusionControllerConfiguration;
-import com.vaadin.fusion.FusionEndpointProperties;
-import com.vaadin.flow.spring.SpringBootAutoConfiguration;
-import com.vaadin.flow.spring.SpringSecurityAutoConfiguration;
+import java.lang.reflect.Method;
+import java.util.Collections;
import org.junit.Assert;
import org.junit.Test;
@@ -20,9 +11,20 @@
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
+import org.springframework.security.web.savedrequest.RequestCache;
+import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
+import com.vaadin.flow.server.HandlerHelper.RequestType;
+import com.vaadin.flow.spring.SpringBootAutoConfiguration;
+import com.vaadin.flow.spring.SpringSecurityAutoConfiguration;
+import com.vaadin.fusion.Endpoint;
+import com.vaadin.fusion.EndpointRegistry;
+import com.vaadin.fusion.FusionControllerConfiguration;
+import com.vaadin.fusion.FusionEndpointProperties;
+
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { FusionEndpointProperties.class })
@ContextConfiguration(classes = { FusionControllerConfiguration.class,
@@ -89,6 +91,73 @@ public void endpointRequestNotSaved() throws Exception {
Assert.assertNull(cache.getRequest(request, response));
}
+ @Test
+ public void getRequest_uses_delegateRequestCache() throws Exception {
+ HttpServletRequest request = RequestUtilTest.createRequest(
+ "/hello-world", null);
+ HttpServletResponse response = createResponse();
+ SavedRequest expectedSavedRequest = Mockito.mock(SavedRequest.class);
+ RequestCache delegateRequestCache = Mockito.mock(RequestCache.class);
+ Mockito.doReturn(expectedSavedRequest).when(delegateRequestCache)
+ .getRequest(request, response);
+ cache.setDelegateRequestCache(delegateRequestCache);
+
+ SavedRequest actualSavedRequest = cache.getRequest(request, response);
+ Mockito.verify(delegateRequestCache).getRequest(request, response);
+ Assert.assertEquals(expectedSavedRequest, actualSavedRequest);
+
+ cache.setDelegateRequestCache(new HttpSessionRequestCache());
+ }
+
+ @Test
+ public void getMatchingRequest_uses_delegateRequestCache()
+ throws Exception {
+ HttpServletRequest request = RequestUtilTest.createRequest(
+ "/hello-world", null);
+ HttpServletResponse response = createResponse();
+ HttpServletRequest expectedMachingRequest = RequestUtilTest.createRequest(
+ "", null);
+ RequestCache delegateRequestCache = Mockito.mock(RequestCache.class);
+ Mockito.doReturn(expectedMachingRequest).when(delegateRequestCache)
+ .getMatchingRequest(request, response);
+ cache.setDelegateRequestCache(delegateRequestCache);
+
+ HttpServletRequest actualMatchingRequest = cache.getMatchingRequest(
+ request, response);
+ Mockito.verify(delegateRequestCache).getMatchingRequest(request, response);
+ Assert.assertEquals(expectedMachingRequest, actualMatchingRequest);
+
+ cache.setDelegateRequestCache(new HttpSessionRequestCache());
+ }
+
+ @Test
+ public void saveRequest_uses_delegateRequestCache() throws Exception {
+ HttpServletRequest request = RequestUtilTest.createRequest(
+ "/hello-world", null);
+ HttpServletResponse response = createResponse();
+ RequestCache delegateRequestCache = Mockito.mock(RequestCache.class);
+ cache.setDelegateRequestCache(delegateRequestCache);
+
+ cache.saveRequest(request, response);
+ Mockito.verify(delegateRequestCache).saveRequest(request, response);
+
+ cache.setDelegateRequestCache(new HttpSessionRequestCache());
+ }
+
+ @Test
+ public void removeRequest_uses_delegateRequestCache() throws Exception {
+ HttpServletRequest request = RequestUtilTest.createRequest(
+ "/hello-world", null);
+ HttpServletResponse response = createResponse();
+ RequestCache delegateRequestCache = Mockito.mock(RequestCache.class);
+ cache.setDelegateRequestCache(delegateRequestCache);
+
+ cache.removeRequest(request, response);
+ Mockito.verify(delegateRequestCache).removeRequest(request, response);
+
+ cache.setDelegateRequestCache(new HttpSessionRequestCache());
+ }
+
private HttpServletResponse createResponse() {
return Mockito.mock(HttpServletResponse.class);
}