Skip to content

Commit 41f26b7

Browse files
majian159eleftherias
authored andcommitted
Improve request matching logic when using cookie
- Repair request cache deleted by mistake - Fix RequestCache throw exception and error redirect. Closes gh-8820 Closes gh-8817
1 parent 97ccbe5 commit 41f26b7

File tree

2 files changed

+60
-10
lines changed

2 files changed

+60
-10
lines changed

web/src/main/java/org/springframework/security/web/savedrequest/CookieRequestCache.java

+40-8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
2222
import org.springframework.security.web.util.matcher.RequestMatcher;
2323
import org.springframework.util.Assert;
24+
import org.springframework.util.MultiValueMap;
25+
import org.springframework.util.StringUtils;
2426
import org.springframework.web.util.UriComponents;
2527
import org.springframework.web.util.UriComponentsBuilder;
2628
import org.springframework.web.util.WebUtils;
@@ -29,6 +31,7 @@
2931
import javax.servlet.http.HttpServletRequest;
3032
import javax.servlet.http.HttpServletResponse;
3133
import java.util.Base64;
34+
import java.util.HashMap;
3235

3336

3437
/**
@@ -52,7 +55,7 @@ public void saveRequest(HttpServletRequest request, HttpServletResponse response
5255
Cookie savedCookie = new Cookie(COOKIE_NAME, encodeCookie(redirectUrl));
5356
savedCookie.setMaxAge(COOKIE_MAX_AGE);
5457
savedCookie.setSecure(request.isSecure());
55-
savedCookie.setPath(request.getContextPath());
58+
savedCookie.setPath(getCookiePath(request));
5659
savedCookie.setHttpOnly(true);
5760

5861
response.addCookie(savedCookie);
@@ -65,7 +68,7 @@ public void saveRequest(HttpServletRequest request, HttpServletResponse response
6568
public SavedRequest getRequest(HttpServletRequest request, HttpServletResponse response) {
6669
Cookie savedRequestCookie = WebUtils.getCookie(request, COOKIE_NAME);
6770
if (savedRequestCookie != null) {
68-
String originalURI = decodeCookie(savedRequestCookie.getValue());
71+
final String originalURI = decodeCookie(savedRequestCookie.getValue());
6972
UriComponents uriComponents = UriComponentsBuilder.fromUriString(originalURI).build();
7073
DefaultSavedRequest.Builder builder = new DefaultSavedRequest.Builder();
7174

@@ -77,32 +80,44 @@ public SavedRequest getRequest(HttpServletRequest request, HttpServletResponse r
7780
port = 80;
7881
}
7982
}
83+
84+
final MultiValueMap<String, String> queryParams = uriComponents.getQueryParams();
85+
86+
if (!queryParams.isEmpty()) {
87+
final HashMap<String, String[]> parameters = new HashMap<>(queryParams.size());
88+
queryParams.forEach((key, value) -> parameters.put(key, value.toArray(new String[]{})));
89+
builder.setParameters(parameters);
90+
}
91+
8092
return builder.setScheme(uriComponents.getScheme())
8193
.setServerName(uriComponents.getHost())
8294
.setRequestURI(uriComponents.getPath())
8395
.setQueryString(uriComponents.getQuery())
8496
.setServerPort(port)
97+
.setMethod(request.getMethod())
8598
.build();
8699
}
87100
return null;
88101
}
89102

90103
@Override
91104
public HttpServletRequest getMatchingRequest(HttpServletRequest request, HttpServletResponse response) {
92-
SavedRequest savedRequest = getRequest(request, response);
93-
if (savedRequest != null) {
94-
removeRequest(request, response);
95-
return new SavedRequestAwareWrapper(savedRequest, request);
105+
SavedRequest saved = this.getRequest(request, response);
106+
if (!this.matchesSavedRequest(request, saved)) {
107+
this.logger.debug("saved request doesn't match");
108+
return null;
109+
} else {
110+
this.removeRequest(request, response);
111+
return new SavedRequestAwareWrapper(saved, request);
96112
}
97-
return null;
98113
}
99114

100115
@Override
101116
public void removeRequest(HttpServletRequest request, HttpServletResponse response) {
102117
Cookie removeSavedRequestCookie = new Cookie(COOKIE_NAME, "");
103118
removeSavedRequestCookie.setSecure(request.isSecure());
104119
removeSavedRequestCookie.setHttpOnly(true);
105-
removeSavedRequestCookie.setPath(request.getContextPath());
120+
removeSavedRequestCookie.setPath(getCookiePath(request));
106121
removeSavedRequestCookie.setMaxAge(0);
107122
response.addCookie(removeSavedRequestCookie);
108123
}
@@ -115,6 +130,23 @@ private static String decodeCookie(String encodedCookieValue) {
115130
return new String(Base64.getDecoder().decode(encodedCookieValue.getBytes()));
116131
}
117132

133+
private static String getCookiePath(HttpServletRequest request) {
134+
final String contextPath = request.getContextPath();
135+
if (StringUtils.isEmpty(contextPath)) {
136+
return "/";
137+
}
138+
return contextPath;
139+
}
140+
141+
private boolean matchesSavedRequest(HttpServletRequest request, SavedRequest savedRequest) {
142+
if (savedRequest == null) {
143+
return false;
144+
} else {
145+
String currentUrl = UrlUtils.buildFullRequestUrl(request);
146+
return savedRequest.getRedirectUrl().equals(currentUrl);
147+
}
148+
}
149+
118150
/**
119151
* Allows selective use of saved requests for a subset of requests. By default any
120152
* request will be cached by the {@code saveRequest} method.

web/src/test/java/org/springframework/security/web/savedrequest/CookieRequestCacheTests.java

+20-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.junit.Test;
1919
import org.springframework.mock.web.MockHttpServletRequest;
2020
import org.springframework.mock.web.MockHttpServletResponse;
21+
import org.springframework.util.StringUtils;
2122

2223
import javax.servlet.http.Cookie;
2324
import javax.servlet.http.HttpServletRequest;
@@ -50,7 +51,7 @@ public void saveRequestWhenMatchesThenSavedRequestInACookieOnResponse() {
5051
assertThat(redirectUrl).isEqualTo("https://abc.com/destination?param1=a&param2=b&param3=1122");
5152

5253
assertThat(savedCookie.getMaxAge()).isEqualTo(-1);
53-
assertThat(savedCookie.getPath()).isEqualTo(request.getContextPath());
54+
assertThat(savedCookie.getPath()).isEqualTo(StringUtils.isEmpty(request.getContextPath()) ? "/" : request.getContextPath());
5455
assertThat(savedCookie.isHttpOnly()).isTrue();
5556
assertThat(savedCookie.getSecure()).isTrue();
5657

@@ -123,7 +124,8 @@ public void matchingRequestWhenRequestDoesNotContainSavedRequestCookieThenReturn
123124
@Test
124125
public void matchingRequestWhenRequestContainsSavedRequestCookieThenSetsAnExpiredCookieInResponse() {
125126
CookieRequestCache cookieRequestCache = new CookieRequestCache();
126-
MockHttpServletRequest request = new MockHttpServletRequest();
127+
MockHttpServletRequest request = requestToSave();
128+
127129
String redirectUrl = "https://abc.com/destination?param1=a&param2=b&param3=1122";
128130
request.setCookies(new Cookie(DEFAULT_COOKIE_NAME, encodeCookie(redirectUrl)));
129131
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -135,6 +137,22 @@ public void matchingRequestWhenRequestContainsSavedRequestCookieThenSetsAnExpire
135137
assertThat(expiredCookie.getMaxAge()).isZero();
136138
}
137139

140+
@Test
141+
public void notMatchingRequestWhenRequestNotContainsSavedRequestCookie() {
142+
CookieRequestCache cookieRequestCache = new CookieRequestCache();
143+
MockHttpServletRequest request = requestToSave();
144+
145+
String redirectUrl = "https://abc.com/api";
146+
request.setCookies(new Cookie(DEFAULT_COOKIE_NAME, encodeCookie(redirectUrl)));
147+
MockHttpServletResponse response = new MockHttpServletResponse();
148+
149+
final HttpServletRequest matchingRequest = cookieRequestCache.getMatchingRequest(request, response);
150+
assertThat(matchingRequest).isNull();
151+
Cookie expiredCookie = response.getCookie(DEFAULT_COOKIE_NAME);
152+
assertThat(expiredCookie).isNull();
153+
154+
}
155+
138156
@Test
139157
public void removeRequestWhenInvokedThenSetsAnExpiredCookieOnResponse() {
140158
CookieRequestCache cookieRequestCache = new CookieRequestCache();

0 commit comments

Comments
 (0)