Fix CookieHttpSessionStrategy encodeUrl
Fix to https://support.pivotal.io/tickets/30469 I do notice 2 bugs in the spring-session code, both inside the CookieHttpSessionStrategy class. The first, using their own sample application, after getting a new session alias from the HttpSessionManager, it calls HttpSessionManager.encodeURL and then stores the output into a request attribute which is later rendered. However, in a Spring MVC application, a Controller may want to issue a redirect to a newly-encoded URL, like this: HttpSessionManager sessionManager = (HttpSessionManager) request.getAttribute(HttpSessionManager.class.getName()); String newSessionAlias = sessionManager.getNewSessionAlias(request); String currentSessionAlias = sessionManager.getCurrentSessionAlias(request); return String.format("redirect:%s", sessionManager.encodeURL("/effectiveUser", newSessionAlias)); The problem here is that Spring MVC will funnel the redirect back through CookieHttpSessionStrategy.MultiSessionHttpServletResponse.encodeRedirect URL, which then looks up the current alias & re-encodes with that alias, effectively replacing the new alias which the controller added. The fix would be for the CookieHttpSessionStrategy.MultiSessionHttpServletResponse to examine the inputted url for the appropriate parameter & don't re-encode if it finds it there. The second issue is that inside CookieHttpSessionStrategy line 346 (return path + "?" + query;) is that if there is no query string (on the default session alias) then the resulting URL will end in a ? with nothing after it. In that situation the ? should be removed as well because the query string is empty.
This commit is contained in:
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -158,7 +159,8 @@ public final class CookieHttpSessionStrategy
|
||||
private CookieSerializer cookieSerializer = new DefaultCookieSerializer();
|
||||
|
||||
/**
|
||||
* The delimiter between a session alias and a session id when reading a cookie value. The default value is " ".
|
||||
* The delimiter between a session alias and a session id when reading a cookie value.
|
||||
* The default value is " ".
|
||||
*/
|
||||
private String deserializationDelimiter = DEFAULT_DELIMITER;
|
||||
|
||||
@@ -307,22 +309,23 @@ public final class CookieHttpSessionStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delimiter between a session alias and a session id when deserializing a cookie. The default is " "
|
||||
* This is useful when using <a href="https://tools.ietf.org/html/rfc6265">RFC
|
||||
* 6265</a> for writing the cookies which doesn't allow for spaces in the cookie
|
||||
* values.
|
||||
* Sets the delimiter between a session alias and a session id when deserializing a
|
||||
* cookie. The default is " " This is useful when using
|
||||
* <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a> for writing the cookies
|
||||
* which doesn't allow for spaces in the cookie values.
|
||||
*
|
||||
* @param delimiter the delimiter to set (i.e. "_ " will try a delimeter of either "_" or " ")
|
||||
* @param delimiter the delimiter to set (i.e. "_ " will try a delimeter of either "_"
|
||||
* or " ")
|
||||
*/
|
||||
public void setDeserializationDelimiter(String delimiter) {
|
||||
this.deserializationDelimiter = delimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delimiter between a session alias and a session id when deserializing a cookie. The default is " ".
|
||||
* This is useful when using <a href="https://tools.ietf.org/html/rfc6265">RFC
|
||||
* 6265</a> for writing the cookies which doesn't allow for spaces in the cookie
|
||||
* values.
|
||||
* Sets the delimiter between a session alias and a session id when deserializing a
|
||||
* cookie. The default is " ". This is useful when using
|
||||
* <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a> for writing the cookies
|
||||
* which doesn't allow for spaces in the cookie values.
|
||||
*
|
||||
* @param delimiter the delimiter to set (i.e. "_")
|
||||
*/
|
||||
@@ -335,7 +338,8 @@ public final class CookieHttpSessionStrategy
|
||||
String sessionCookieValue = cookieValues.isEmpty() ? ""
|
||||
: cookieValues.iterator().next();
|
||||
Map<String, String> result = new LinkedHashMap<String, String>();
|
||||
StringTokenizer tokens = new StringTokenizer(sessionCookieValue, this.deserializationDelimiter);
|
||||
StringTokenizer tokens = new StringTokenizer(sessionCookieValue,
|
||||
this.deserializationDelimiter);
|
||||
if (tokens.countTokens() == 1) {
|
||||
result.put(DEFAULT_ALIAS, tokens.nextToken());
|
||||
return result;
|
||||
@@ -375,12 +379,16 @@ public final class CookieHttpSessionStrategy
|
||||
String replacement = isDefaultAlias ? "" : "$1" + encodedSessionAlias;
|
||||
query = query.replaceFirst("((^|&)" + this.sessionParam + "=)([^&]+)?",
|
||||
replacement);
|
||||
if (!isDefaultAlias && url.endsWith(query)) {
|
||||
String sessionParamReplacement = String.format("%s=%s", this.sessionParam,
|
||||
encodedSessionAlias);
|
||||
|
||||
if (!isDefaultAlias && !query.contains(sessionParamReplacement)
|
||||
&& url.endsWith(query)) {
|
||||
// no existing alias
|
||||
if (!(query.endsWith("&") || query.length() == 0)) {
|
||||
query += "&";
|
||||
}
|
||||
query += this.sessionParam + "=" + encodedSessionAlias;
|
||||
query += sessionParamReplacement;
|
||||
}
|
||||
|
||||
return path + "?" + query;
|
||||
@@ -407,19 +415,43 @@ public final class CookieHttpSessionStrategy
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
private String getCurrentSessionAliasFromUrl(String url) {
|
||||
String currentSessionAliasFromUrl = null;
|
||||
int queryStart = url.indexOf("?");
|
||||
|
||||
if (queryStart >= 0) {
|
||||
String query = url.substring(queryStart + 1);
|
||||
Matcher matcher = Pattern
|
||||
.compile(String.format("%s=([^&]+)",
|
||||
CookieHttpSessionStrategy.this.sessionParam))
|
||||
.matcher(query);
|
||||
|
||||
if (matcher.find()) {
|
||||
currentSessionAliasFromUrl = matcher.group(1);
|
||||
}
|
||||
}
|
||||
|
||||
return currentSessionAliasFromUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeRedirectURL(String url) {
|
||||
url = super.encodeRedirectURL(url);
|
||||
return CookieHttpSessionStrategy.this.encodeURL(url,
|
||||
getCurrentSessionAlias(this.request));
|
||||
String encodedUrl = super.encodeRedirectURL(url);
|
||||
String currentSessionAliasFromUrl = getCurrentSessionAliasFromUrl(encodedUrl);
|
||||
String alias = (currentSessionAliasFromUrl != null)
|
||||
? currentSessionAliasFromUrl : getCurrentSessionAlias(this.request);
|
||||
|
||||
return CookieHttpSessionStrategy.this.encodeURL(encodedUrl, alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeURL(String url) {
|
||||
url = super.encodeURL(url);
|
||||
String encodedUrl = super.encodeURL(url);
|
||||
String currentSessionAliasFromUrl = getCurrentSessionAliasFromUrl(encodedUrl);
|
||||
String alias = (currentSessionAliasFromUrl != null)
|
||||
? currentSessionAliasFromUrl : getCurrentSessionAlias(this.request);
|
||||
|
||||
String alias = getCurrentSessionAlias(this.request);
|
||||
return CookieHttpSessionStrategy.this.encodeURL(url, alias);
|
||||
return CookieHttpSessionStrategy.this.encodeURL(encodedUrl, alias);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user