Align HttpSessionStrategy with WebSessionIdResolver

This commit simplifies `HttpSessionStrategy` API by aligning it with Spring Framework's `WebSessionIdResolver`. As a part of this, support for managing multiple users' sessions has been removed.

Closes gh-275
Closes gh-362
This commit is contained in:
Vedran Pavic
2017-10-25 20:42:29 +02:00
committed by Rob Winch
parent 2ecb2e60c0
commit cd394bbe10
33 changed files with 176 additions and 2635 deletions

View File

@@ -42,7 +42,6 @@ import org.springframework.session.web.http.CookieHttpSessionStrategy;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.session.web.http.HttpSessionStrategy;
import org.springframework.session.web.http.MultiHttpSessionStrategy;
import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.util.ClassUtils;
@@ -127,16 +126,11 @@ public class SpringHttpSessionConfiguration implements ApplicationContextAware {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(
sessionRepository);
sessionRepositoryFilter.setServletContext(this.servletContext);
if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy(
(MultiHttpSessionStrategy) this.httpSessionStrategy);
}
else {
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
}
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
return sessionRepositoryFilter;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
if (ClassUtils.isPresent(

View File

@@ -16,20 +16,10 @@
package org.springframework.session.web.http;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.LinkedHashMap;
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;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.springframework.session.Session;
import org.springframework.session.web.http.CookieSerializer.CookieValue;
@@ -68,222 +58,38 @@ import org.springframework.session.web.http.CookieSerializer.CookieValue;
* Set-Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6; Expires=Thur, 1 Jan 1970 00:00:00 GMT; Secure; HttpOnly
* </pre>
*
* <h2>Supporting Multiple Simultaneous Sessions</h2>
*
* <p>
* By default multiple sessions are also supported. Once a session is established with the
* browser, another session can be initiated by specifying a unique value for the
* {@link #setSessionAliasParamName(String)}. For example, a request to:
* </p>
*
* <pre>
* GET /messages/?_s=1416195761178 HTTP/1.1
* Host: example.com
* Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6
* </pre>
*
* Will result in the following response:
*
* <pre>
* HTTP/1.1 200 OK
* Set-Cookie: SESSION="0 f81d4fae-7dec-11d0-a765-00a0c91e6bf6 1416195761178 8a929cde-2218-4557-8d4e-82a79a37876d"; Expires=Thur, 1 Jan 1970 00:00:00 GMT; Secure; HttpOnly
* </pre>
*
* <p>
* To use the original session a request without the HTTP parameter u can be made. To use
* the new session, a request with the HTTP parameter _s=1416195761178 can be used. By
* default URLs will be rewritten to include the currently selected session.
* </p>
*
* <h2>Selecting Sessions</h2>
*
* <p>
* Sessions can be managed by using the HttpSessionManager and SessionRepository. If you
* are not using Spring in the rest of your application you can obtain a reference from
* the HttpServletRequest attributes. An example is provided below:
* </p>
*
* <code>
* HttpSessionManager sessionManager =
* (HttpSessionManager) req.getAttribute(HttpSessionManager.class.getName());
* SessionRepository&lt;Session&gt; repo =
* (SessionRepository&lt;Session&gt;) req.getAttribute(SessionRepository.class.getName());
*
* String currentSessionAlias = sessionManager.getCurrentSessionAlias(req);
* Map&lt;String, String&gt; sessionIds = sessionManager.getSessionIds(req);
* String newSessionAlias = String.valueOf(System.currentTimeMillis());
*
* String contextPath = req.getContextPath();
* List&lt;Account&gt; accounts = new ArrayList&lt;&gt;();
* Account currentAccount = null; for(Map.Entry&lt;String, String&gt; entry :
* sessionIds.entrySet()) { String alias = entry.getKey(); String sessionId =
* entry.getValue();
* </code>
*
* Session session = repo.findById(sessionId); if(session == null) { continue; }
*
* String username = session.getAttribute("username"); if(username == null) {
* newSessionAlias = alias; continue; }
*
* String logoutUrl = sessionManager.encodeURL("./logout", alias); String switchAccountUrl
* = sessionManager.encodeURL("./", alias); Account account = new Account(username,
* logoutUrl, switchAccountUrl); if(currentSessionAlias.equals(alias)) { currentAccount =
* account; } else { accounts.add(account); } }
*
* req.setAttribute("currentAccount", currentAccount); req.setAttribute("addAccountUrl",
* sessionManager.encodeURL(contextPath, newSessionAlias)); req.setAttribute("accounts",
* accounts); }
*
*
* @author Rob Winch
* @author Vedran Pavic
* @since 1.0
*/
public final class CookieHttpSessionStrategy
implements MultiHttpSessionStrategy, HttpSessionManager {
/**
* The default delimiter for both serialization and deserialization.
*/
private static final String DEFAULT_DELIMITER = " ";
public final class CookieHttpSessionStrategy implements HttpSessionStrategy {
private static final String SESSION_IDS_WRITTEN_ATTR = CookieHttpSessionStrategy.class
.getName().concat(".SESSIONS_WRITTEN_ATTR");
static final String DEFAULT_ALIAS = "0";
static final String DEFAULT_SESSION_ALIAS_PARAM_NAME = "_s";
private static final Pattern ALIAS_PATTERN = Pattern.compile("^[\\w-]{1,50}$");
private String sessionParam = DEFAULT_SESSION_ALIAS_PARAM_NAME;
private static final String WRITTEN_SESSION_ID_ATTR = CookieHttpSessionStrategy.class
.getName().concat(".WRITTEN_SESSION_ID_ATTR");
private CookieSerializer cookieSerializer = new DefaultCookieSerializer();
/**
* The delimiter between a session alias and a session id when reading a cookie value.
* The default value is " ".
*/
private String deserializationDelimiter = DEFAULT_DELIMITER;
/**
* The delimiter between a session alias and a session id when writing a cookie value.
* The default is " ".
*/
private String serializationDelimiter = DEFAULT_DELIMITER;
public String getRequestedSessionId(HttpServletRequest request) {
Map<String, String> sessionIds = getSessionIds(request);
String sessionAlias = getCurrentSessionAlias(request);
return sessionIds.get(sessionAlias);
}
public String getCurrentSessionAlias(HttpServletRequest request) {
if (this.sessionParam == null) {
return DEFAULT_ALIAS;
}
String u = request.getParameter(this.sessionParam);
if (u == null) {
return DEFAULT_ALIAS;
}
if (!ALIAS_PATTERN.matcher(u).matches()) {
return DEFAULT_ALIAS;
}
return u;
}
public String getNewSessionAlias(HttpServletRequest request) {
Set<String> sessionAliases = getSessionIds(request).keySet();
if (sessionAliases.isEmpty()) {
return DEFAULT_ALIAS;
}
long lastAlias = Long.decode(DEFAULT_ALIAS);
for (String alias : sessionAliases) {
long selectedAlias = safeParse(alias);
if (selectedAlias > lastAlias) {
lastAlias = selectedAlias;
}
}
return Long.toHexString(lastAlias + 1);
}
private long safeParse(String hex) {
try {
return Long.decode("0x" + hex);
}
catch (NumberFormatException notNumber) {
return 0;
}
@Override
public List<String> getRequestedSessionIds(HttpServletRequest request) {
return this.cookieSerializer.readCookieValues(request);
}
@Override
public void onNewSession(Session session, HttpServletRequest request,
HttpServletResponse response) {
Set<String> sessionIdsWritten = getSessionIdsWritten(request);
if (sessionIdsWritten.contains(session.getId())) {
String sessionId = session.getId();
if (sessionId.equals(request.getAttribute(WRITTEN_SESSION_ID_ATTR))) {
return;
}
sessionIdsWritten.add(session.getId());
Map<String, String> sessionIds = getSessionIds(request);
String sessionAlias = getCurrentSessionAlias(request);
sessionIds.put(sessionAlias, session.getId());
String cookieValue = createSessionCookieValue(sessionIds);
request.setAttribute(WRITTEN_SESSION_ID_ATTR, sessionId);
this.cookieSerializer
.writeCookieValue(new CookieValue(request, response, cookieValue));
}
@SuppressWarnings("unchecked")
private Set<String> getSessionIdsWritten(HttpServletRequest request) {
Set<String> sessionsWritten = (Set<String>) request
.getAttribute(SESSION_IDS_WRITTEN_ATTR);
if (sessionsWritten == null) {
sessionsWritten = new HashSet<>();
request.setAttribute(SESSION_IDS_WRITTEN_ATTR, sessionsWritten);
}
return sessionsWritten;
}
private String createSessionCookieValue(Map<String, String> sessionIds) {
if (sessionIds.isEmpty()) {
return "";
}
if (sessionIds.size() == 1 && sessionIds.keySet().contains(DEFAULT_ALIAS)) {
return sessionIds.values().iterator().next();
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : sessionIds.entrySet()) {
String alias = entry.getKey();
String id = entry.getValue();
sb.append(alias);
sb.append(this.serializationDelimiter);
sb.append(id);
sb.append(this.serializationDelimiter);
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
.writeCookieValue(new CookieValue(request, response, sessionId));
}
@Override
public void onInvalidateSession(HttpServletRequest request,
HttpServletResponse response) {
Map<String, String> sessionIds = getSessionIds(request);
String requestedAlias = getCurrentSessionAlias(request);
sessionIds.remove(requestedAlias);
String cookieValue = createSessionCookieValue(sessionIds);
this.cookieSerializer
.writeCookieValue(new CookieValue(request, response, cookieValue));
}
/**
* Sets the name of the HTTP parameter that is used to specify the session alias. If
* the value is null, then only a single session is supported per browser.
*
* @param sessionAliasParamName the name of the HTTP parameter used to specify the
* session alias. If null, then ony a single session is supported per browser.
*/
public void setSessionAliasParamName(String sessionAliasParamName) {
this.sessionParam = sessionAliasParamName;
this.cookieSerializer.writeCookieValue(new CookieValue(request, response, ""));
}
/**
@@ -298,151 +104,4 @@ public final class CookieHttpSessionStrategy
this.cookieSerializer = cookieSerializer;
}
/**
* 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 " ")
*/
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.
*
* @param delimiter the delimiter to set (i.e. "_")
*/
public void setSerializationDelimiter(String delimiter) {
this.serializationDelimiter = delimiter;
}
public Map<String, String> getSessionIds(HttpServletRequest request) {
List<String> cookieValues = this.cookieSerializer.readCookieValues(request);
String sessionCookieValue = cookieValues.isEmpty() ? ""
: cookieValues.iterator().next();
Map<String, String> result = new LinkedHashMap<>();
StringTokenizer tokens = new StringTokenizer(sessionCookieValue,
this.deserializationDelimiter);
if (tokens.countTokens() == 1) {
result.put(DEFAULT_ALIAS, tokens.nextToken());
return result;
}
while (tokens.hasMoreTokens()) {
String alias = tokens.nextToken();
if (!tokens.hasMoreTokens()) {
break;
}
String id = tokens.nextToken();
result.put(alias, id);
}
return result;
}
public HttpServletRequest wrapRequest(HttpServletRequest request,
HttpServletResponse response) {
request.setAttribute(HttpSessionManager.class.getName(), this);
return request;
}
public HttpServletResponse wrapResponse(HttpServletRequest request,
HttpServletResponse response) {
return new MultiSessionHttpServletResponse(response, request);
}
public String encodeURL(String url, String sessionAlias) {
String encodedSessionAlias = urlEncode(sessionAlias);
int queryStart = url.indexOf("?");
boolean isDefaultAlias = DEFAULT_ALIAS.equals(encodedSessionAlias);
if (queryStart < 0) {
return isDefaultAlias ? url
: url + "?" + this.sessionParam + "=" + encodedSessionAlias;
}
String path = url.substring(0, queryStart);
String query = url.substring(queryStart + 1, url.length());
String replacement = isDefaultAlias ? "" : "$1" + encodedSessionAlias;
query = query.replaceFirst("((^|&)" + this.sessionParam + "=)([^&]+)?",
replacement);
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 += sessionParamReplacement;
}
return path + "?" + query;
}
private String urlEncode(String value) {
try {
return URLEncoder.encode(value, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* A {@link CookieHttpSessionStrategy} aware {@link HttpServletResponseWrapper}.
*/
class MultiSessionHttpServletResponse extends HttpServletResponseWrapper {
private final HttpServletRequest request;
MultiSessionHttpServletResponse(HttpServletResponse response,
HttpServletRequest request) {
super(response);
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) {
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) {
String encodedUrl = super.encodeURL(url);
String currentSessionAliasFromUrl = getCurrentSessionAliasFromUrl(encodedUrl);
String alias = (currentSessionAliasFromUrl != null)
? currentSessionAliasFromUrl : getCurrentSessionAlias(this.request);
return CookieHttpSessionStrategy.this.encodeURL(encodedUrl, alias);
}
}
}

View File

@@ -16,6 +16,9 @@
package org.springframework.session.web.http;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -52,21 +55,27 @@ import org.springframework.session.Session;
* </pre>
*
* @author Rob Winch
* @author Vedran Pavic
* @since 1.0
*/
public class HeaderHttpSessionStrategy implements HttpSessionStrategy {
private String headerName = "X-Auth-Token";
public String getRequestedSessionId(HttpServletRequest request) {
return request.getHeader(this.headerName);
@Override
public List<String> getRequestedSessionIds(HttpServletRequest request) {
String headerValue = request.getHeader(this.headerName);
return headerValue != null ? Collections.singletonList(headerValue)
: Collections.emptyList();
}
@Override
public void onNewSession(Session session, HttpServletRequest request,
HttpServletResponse response) {
response.setHeader(this.headerName, session.getId());
}
@Override
public void onInvalidateSession(HttpServletRequest request,
HttpServletResponse response) {
response.setHeader(this.headerName, "");

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2014-2016 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
*
* http://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.session.web.http;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
/**
* Allows managing a mapping of alias to the session id for having multiple active
* sessions at the same time.
*
* @author Rob Winch
* @since 1.0
*
*/
public interface HttpSessionManager {
/**
* Gets the current session's alias from the {@link HttpServletRequest}.
*
* @param request the {@link HttpServletRequest} to obtain the current session's alias
* from.
* @return the current sessions' alias. Cannot be null.
*/
String getCurrentSessionAlias(HttpServletRequest request);
/**
* Gets a mapping of the session alias to the session id from the
* {@link HttpServletRequest}.
*
* @param request the {@link HttpServletRequest} to obtain the mapping from. Cannot be
* null.
* @return a mapping of the session alias to the session id from the
* {@link HttpServletRequest}. Cannot be null.
*/
Map<String, String> getSessionIds(HttpServletRequest request);
/**
* Provides the ability to encode the URL for a given session alias.
*
* @param url the url to encode.
* @param sessionAlias the session alias to encode.
* @return the encoded URL
*/
String encodeURL(String url, String sessionAlias);
/**
* Gets a new and unique Session alias. Typically this will be called to pass into
* {@code HttpSessionManager#encodeURL(java.lang.String)}. For example:
*
* <code>
* String newAlias = httpSessionManager.getNewSessionAlias(request);
* String addAccountUrl = httpSessionManager.encodeURL("./", newAlias);
* </code>
*
* @param request the {@link HttpServletRequest} to get a new alias from
* @return Gets a new and unique Session alias.
*/
String getNewSessionAlias(HttpServletRequest request);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2017 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.
@@ -16,6 +16,8 @@
package org.springframework.session.web.http;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -25,6 +27,7 @@ import org.springframework.session.Session;
* A strategy for mapping HTTP request and responses to a {@link Session}.
*
* @author Rob Winch
* @author Vedran Pavic
* @since 1.0
*/
public interface HttpSessionStrategy {
@@ -36,10 +39,9 @@ public interface HttpSessionStrategy {
*
* @param request the {@link javax.servlet.http.HttpServletRequest} to obtain the
* session id from. Cannot be null.
* @return the {@link javax.servlet.http.HttpServletRequest} to obtain the session id
* from.
* @return the session ids
*/
String getRequestedSessionId(HttpServletRequest request);
List<String> getRequestedSessionIds(HttpServletRequest request);
/**
* This method is invoked when a new session is created and should inform a client
@@ -76,4 +78,5 @@ public interface HttpSessionStrategy {
* the {@link org.springframework.session.Session} Cannot be null.
*/
void onInvalidateSession(HttpServletRequest request, HttpServletResponse response);
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2014-2016 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
*
* http://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.session.web.http;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* <p>
* Some {@link HttpSessionStrategy} may also want to further customize
* {@link HttpServletRequest} and {@link HttpServletResponse} objects. For example,
* {@link CookieHttpSessionStrategy} customizes how URL rewriting is done to select which
* session should be used in the event multiple sessions are active.
* </p>
*
* @author Rob Winch
* @since 1.0
* @see CookieHttpSessionStrategy
*/
public interface MultiHttpSessionStrategy
extends HttpSessionStrategy, RequestResponsePostProcessor {
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2014-2016 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
*
* http://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.session.web.http;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Allows customizing the {@link HttpServletRequest} and/or the
* {@link HttpServletResponse}.
*
* @author Rob Winch
* @since 1.0
*/
public interface RequestResponsePostProcessor {
/**
* Allows customizing the {@link HttpServletRequest}.
*
* @param request the original {@link HttpServletRequest}. Cannot be null.
* @param response the original {@link HttpServletResponse}. This is NOT the result of
* {@link #wrapResponse(HttpServletRequest, HttpServletResponse)} Cannot be null. .
* @return a non-null {@link HttpServletRequest}
*/
HttpServletRequest wrapRequest(HttpServletRequest request,
HttpServletResponse response);
/**
* Allows customizing the {@link HttpServletResponse}.
*
* @param request the original {@link HttpServletRequest}. This is NOT the result of
* {@link #wrapRequest(HttpServletRequest, HttpServletResponse)}. Cannot be null.
* @param response the original {@link HttpServletResponse}. Cannot be null.
* @return a non-null {@link HttpServletResponse}
*/
HttpServletResponse wrapResponse(HttpServletRequest request,
HttpServletResponse response);
}

View File

@@ -51,10 +51,10 @@ import org.springframework.session.SessionRepository;
*
* <ul>
* <li>The session id is looked up using
* {@link HttpSessionStrategy#getRequestedSessionId(javax.servlet.http.HttpServletRequest)}
* {@link HttpSessionStrategy#getRequestedSessionIds(javax.servlet.http.HttpServletRequest)}
* . The default is to look in a cookie named SESSION.</li>
* <li>The session id of newly created {@link org.springframework.session.Session}
* is sent to the client using
* <li>The session id of newly created {@link org.springframework.session.Session} is sent
* to the client using
* <li>The client is notified that the session id is no longer valid with
* {@link HttpSessionStrategy#onInvalidateSession(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
* </li>
@@ -69,10 +69,11 @@ import org.springframework.session.SessionRepository;
* @param <S> the {@link Session} type.
* @since 1.0
* @author Rob Winch
* @author Vedran Pavic
*/
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
public class SessionRepositoryFilter<S extends Session>
extends OncePerRequestFilter {
public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFilter {
private static final String SESSION_LOGGER_NAME = SessionRepositoryFilter.class
.getName().concat(".SESSION_LOGGER");
@@ -102,7 +103,7 @@ public class SessionRepositoryFilter<S extends Session>
private ServletContext servletContext;
private MultiHttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy();
private HttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy();
/**
* Creates a new instance.
@@ -123,21 +124,6 @@ public class SessionRepositoryFilter<S extends Session>
* @param httpSessionStrategy the {@link HttpSessionStrategy} to use. Cannot be null.
*/
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
if (httpSessionStrategy == null) {
throw new IllegalArgumentException("httpSessionStrategy cannot be null");
}
this.httpSessionStrategy = new MultiHttpSessionStrategyAdapter(
httpSessionStrategy);
}
/**
* Sets the {@link MultiHttpSessionStrategy} to be used. The default is a
* {@link CookieHttpSessionStrategy}.
*
* @param httpSessionStrategy the {@link MultiHttpSessionStrategy} to use. Cannot be
* null.
*/
public void setHttpSessionStrategy(MultiHttpSessionStrategy httpSessionStrategy) {
if (httpSessionStrategy == null) {
throw new IllegalArgumentException("httpSessionStrategy cannot be null");
}
@@ -155,13 +141,8 @@ public class SessionRepositoryFilter<S extends Session>
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
wrappedRequest, response);
HttpServletRequest strategyRequest = this.httpSessionStrategy
.wrapRequest(wrappedRequest, wrappedResponse);
HttpServletResponse strategyResponse = this.httpSessionStrategy
.wrapResponse(wrappedRequest, wrappedResponse);
try {
filterChain.doFilter(strategyRequest, strategyResponse);
filterChain.doFilter(wrappedRequest, wrappedResponse);
}
finally {
wrappedRequest.commitSession();
@@ -213,9 +194,13 @@ public class SessionRepositoryFilter<S extends Session>
*/
private final class SessionRepositoryRequestWrapper
extends HttpServletRequestWrapper {
private Boolean requestedSessionIdValid;
private boolean requestedSessionInvalidated;
private final HttpServletResponse response;
private final ServletContext servletContext;
private SessionRepositoryRequestWrapper(HttpServletRequest request,
@@ -262,6 +247,7 @@ public class SessionRepositoryFilter<S extends Session>
}
}
@Override
@SuppressWarnings("unused")
public String changeSessionId() {
HttpSession session = getSession(false);
@@ -313,25 +299,24 @@ public class SessionRepositoryFilter<S extends Session>
return currentSession;
}
String requestedSessionId = getRequestedSessionId();
if (requestedSessionId != null
&& getAttribute(INVALID_SESSION_ID_ATTR) == null) {
S session = getSession(requestedSessionId);
if (session != null) {
if (requestedSessionId != null) {
if (getAttribute(INVALID_SESSION_ID_ATTR) == null) {
S session = getSession(requestedSessionId);
this.requestedSessionIdValid = true;
currentSession = new HttpSessionWrapper(session, getServletContext());
currentSession.setNew(false);
setCurrentSession(currentSession);
return currentSession;
}
else {
// This is an invalid session id. No need to ask again if
// request.getSession is invoked for the duration of this request
if (SESSION_LOGGER.isDebugEnabled()) {
SESSION_LOGGER.debug(
"No session found by id: Caching result for getSession(false) for this HttpServletRequest.");
}
setAttribute(INVALID_SESSION_ID_ATTR, "true");
}
else {
// This is an invalid session id. No need to ask again if
// request.getSession is invoked for the duration of this request
if (SESSION_LOGGER.isDebugEnabled()) {
SESSION_LOGGER.debug(
"No session found by id: Caching result for getSession(false) for this HttpServletRequest.");
}
setAttribute(INVALID_SESSION_ID_ATTR, "true");
}
if (!create) {
return null;
@@ -367,7 +352,10 @@ public class SessionRepositoryFilter<S extends Session>
@Override
public String getRequestedSessionId() {
return SessionRepositoryFilter.this.httpSessionStrategy
.getRequestedSessionId(this);
.getRequestedSessionIds(this).stream()
.filter(sessionId -> SessionRepositoryFilter.this.sessionRepository
.findById(sessionId) != null)
.findFirst().orElse(null);
}
/**
@@ -390,44 +378,7 @@ public class SessionRepositoryFilter<S extends Session>
SessionRepositoryFilter.this.sessionRepository.deleteById(getId());
}
}
}
/**
* A delegating implementation of {@link MultiHttpSessionStrategy}.
*/
static class MultiHttpSessionStrategyAdapter implements MultiHttpSessionStrategy {
private HttpSessionStrategy delegate;
/**
* Create a new {@link MultiHttpSessionStrategyAdapter} instance.
* @param delegate the delegate HTTP session strategy
*/
MultiHttpSessionStrategyAdapter(HttpSessionStrategy delegate) {
this.delegate = delegate;
}
public String getRequestedSessionId(HttpServletRequest request) {
return this.delegate.getRequestedSessionId(request);
}
public void onNewSession(Session session, HttpServletRequest request,
HttpServletResponse response) {
this.delegate.onNewSession(session, request, response);
}
public void onInvalidateSession(HttpServletRequest request,
HttpServletResponse response) {
this.delegate.onInvalidateSession(request, response);
}
public HttpServletRequest wrapRequest(HttpServletRequest request,
HttpServletResponse response) {
return request;
}
public HttpServletResponse wrapResponse(HttpServletRequest request,
HttpServletResponse response) {
return response;
}
}
}

View File

@@ -17,8 +17,7 @@
package org.springframework.session.config.annotation.web.http;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Collections;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
@@ -35,8 +34,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.session.MapSessionRepository;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.CookieSerializer.CookieValue;
import org.springframework.session.web.http.SessionRepositoryFilter;
@@ -46,6 +46,7 @@ import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -72,6 +73,9 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests {
@Autowired
private SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;
@Autowired
private SessionRepository sessionRepository;
@Autowired
private CookieSerializer cookieSerializer;
@@ -84,7 +88,9 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests {
public void usesReadSessionIds() throws Exception {
String sessionId = "sessionId";
given(this.cookieSerializer.readCookieValues(any(HttpServletRequest.class)))
.willReturn(Arrays.asList(sessionId));
.willReturn(Collections.singletonList(sessionId));
given(this.sessionRepository.findById(anyString()))
.willReturn(new MapSession(sessionId));
this.sessionRepositoryFilter.doFilter(this.request, this.response, this.chain);
@@ -93,6 +99,8 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests {
@Test
public void usesWrite() throws Exception {
given(this.sessionRepository.findById(anyString())).willReturn(new MapSession());
this.sessionRepositoryFilter.doFilter(this.request, this.response,
new MockFilterChain() {
@@ -116,8 +124,8 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests {
static class Config {
@Bean
public MapSessionRepository mapSessionRepository() {
return new MapSessionRepository(new ConcurrentHashMap<>());
public SessionRepository sessionRepository() {
return mock(SessionRepository.class);
}
@Bean

View File

@@ -1,108 +0,0 @@
/*
* Copyright 2014-2017 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
*
* http://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.session.config.annotation.web.http;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.session.MapSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.web.http.MultiHttpSessionStrategy;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link SpringHttpSessionConfiguration} using a custom
* {@link MultiHttpSessionStrategy}.
*
* @author Rob Winch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests {
@Autowired
private MockHttpServletRequest request;
@Autowired
private MockHttpServletResponse response;
private MockFilterChain chain;
@Autowired
private SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;
@Autowired
private MultiHttpSessionStrategy strategy;
@Before
public void setup() {
this.chain = new MockFilterChain();
}
@Test
public void wrapRequestAndResponseUsed() throws Exception {
given(this.strategy.wrapRequest(any(HttpServletRequest.class),
any(HttpServletResponse.class))).willReturn(this.request);
given(this.strategy.wrapResponse(any(HttpServletRequest.class),
any(HttpServletResponse.class))).willReturn(this.response);
this.sessionRepositoryFilter.doFilter(this.request, this.response, this.chain);
verify(this.strategy).wrapRequest(any(HttpServletRequest.class),
any(HttpServletResponse.class));
verify(this.strategy).wrapResponse(any(HttpServletRequest.class),
any(HttpServletResponse.class));
}
@EnableSpringHttpSession
@Configuration
static class Config {
@Bean
public MapSessionRepository mapSessionRepository() {
return new MapSessionRepository(new ConcurrentHashMap<>());
}
@Bean
public MultiHttpSessionStrategy strategy() {
return mock(MultiHttpSessionStrategy.class);
}
}
}

View File

@@ -17,10 +17,9 @@
package org.springframework.session.web.http;
import java.util.Base64;
import java.util.Map;
import java.util.Collections;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.junit.Before;
import org.junit.Test;
@@ -32,7 +31,11 @@ import org.springframework.session.Session;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link CookieHttpSessionStrategy}.
*/
public class CookieHttpSessionStrategyTests {
private MockHttpServletRequest request;
private MockHttpServletResponse response;
@@ -51,22 +54,22 @@ public class CookieHttpSessionStrategyTests {
@Test
public void getRequestedSessionIdNull() throws Exception {
assertThat(this.strategy.getRequestedSessionId(this.request)).isNull();
assertThat(this.strategy.getRequestedSessionIds(this.request)).isEmpty();
}
@Test
public void getRequestedSessionIdNotNull() throws Exception {
setSessionCookie(this.session.getId());
assertThat(this.strategy.getRequestedSessionId(this.request))
.isEqualTo(this.session.getId());
assertThat(this.strategy.getRequestedSessionIds(this.request))
.isEqualTo(Collections.singletonList(this.session.getId()));
}
@Test
public void getRequestedSessionIdNotNullCustomCookieName() throws Exception {
setCookieName("CUSTOM");
setSessionCookie(this.session.getId());
assertThat(this.strategy.getRequestedSessionId(this.request))
.isEqualTo(this.session.getId());
assertThat(this.strategy.getRequestedSessionIds(this.request))
.isEqualTo(Collections.singletonList(this.session.getId()));
}
@Test
@@ -97,46 +100,6 @@ public class CookieHttpSessionStrategyTests {
assertThat(base64Decode(cookies[1].getValue())).isEqualTo(newSession.getId());
}
@Test
public void onNewSessionExistingSessionSameAlias() throws Exception {
Session existing = new MapSession();
setSessionCookie(existing.getId());
this.strategy.onNewSession(this.session, this.request, this.response);
assertThat(getSessionId()).isEqualTo(this.session.getId());
}
@Test
public void onNewSessionExistingSessionNewAlias() throws Exception {
Session existing = new MapSession();
setSessionCookie(existing.getId());
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
this.strategy.onNewSession(this.session, this.request, this.response);
assertThat(getSessionId())
.isEqualTo("0 " + existing.getId() + " new " + this.session.getId());
}
@Test
public void onNewSessionExistingSessionNewAliasCustomDelimiter() throws Exception {
this.strategy.setSerializationDelimiter("_");
Session existing = new MapSession();
setSessionCookie(existing.getId());
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
this.strategy.onNewSession(this.session, this.request, this.response);
assertThat(getSessionId())
.isEqualTo("0_" + existing.getId() + "_new_" + this.session.getId());
}
// gh-321
@Test
public void onNewSessionExplicitAlias() throws Exception {
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
this.strategy.onNewSession(this.session, this.request, this.response);
assertThat(getSessionId()).isEqualTo("new " + this.session.getId());
}
@Test
public void onNewSessionCookiePath() throws Exception {
this.request.setContextPath("/somethingunique");
@@ -177,533 +140,12 @@ public class CookieHttpSessionStrategyTests {
assertThat(getSessionId()).isEmpty();
}
@Test
public void onDeleteSessionExistingSessionSameAlias() throws Exception {
Session existing = new MapSession();
setSessionCookie("0 " + existing.getId() + " new " + this.session.getId());
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
this.strategy.onInvalidateSession(this.request, this.response);
assertThat(getSessionId()).isEqualTo(existing.getId());
}
@Test
public void onDeleteSessionExistingSessionNewAlias() throws Exception {
Session existing = new MapSession();
setSessionCookie("0 " + existing.getId() + " new " + this.session.getId());
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
this.strategy.onInvalidateSession(this.request, this.response);
assertThat(getSessionId()).isEqualTo(existing.getId());
}
@Test
public void encodeURLNoExistingQuery() {
assertThat(this.strategy.encodeURL("/url", "2")).isEqualTo("/url?_s=2");
}
@Test
public void encodeURLNoExistingQueryEmpty() {
assertThat(this.strategy.encodeURL("/url?", "2")).isEqualTo("/url?_s=2");
}
@Test
public void encodeURLExistingQueryNoAlias() {
assertThat(this.strategy.encodeURL("/url?a=b", "2")).isEqualTo("/url?a=b&_s=2");
}
@Test
public void encodeURLExistingQueryExistingAliasStart() {
assertThat(this.strategy.encodeURL("/url?_s=1&y=z", "2"))
.isEqualTo("/url?_s=2&y=z");
}
@Test
public void encodeURLExistingQueryExistingAliasMiddle() {
assertThat(this.strategy.encodeURL("/url?a=b&_s=1&y=z", "2"))
.isEqualTo("/url?a=b&_s=2&y=z");
}
@Test
public void encodeURLExistingQueryExistingAliasEnd() {
assertThat(this.strategy.encodeURL("/url?a=b&_s=1", "2"))
.isEqualTo("/url?a=b&_s=2");
}
//
@Test
public void encodeURLExistingQueryParamEndsWithActualParamStart() {
assertThat(this.strategy.encodeURL("/url?x_s=1&y=z", "2"))
.isEqualTo("/url?x_s=1&y=z&_s=2");
}
@Test
public void encodeURLExistingQueryParamEndsWithActualParamMiddle() {
assertThat(this.strategy.encodeURL("/url?a=b&x_s=1&y=z", "2"))
.isEqualTo("/url?a=b&x_s=1&y=z&_s=2");
}
@Test
public void encodeURLExistingQueryParamEndsWithActualParamEnd() {
assertThat(this.strategy.encodeURL("/url?a=b&x_s=1", "2"))
.isEqualTo("/url?a=b&x_s=1&_s=2");
}
//
@Test
public void encodeURLNoExistingQueryDefaultAlias() {
assertThat(this.strategy.encodeURL("/url", "0")).isEqualTo("/url");
}
@Test
public void encodeURLNoExistingQueryEmptyDefaultAlias() {
assertThat(this.strategy.encodeURL("/url?", "0")).isEqualTo("/url?");
}
@Test
public void encodeURLExistingQueryNoAliasDefaultAlias() {
assertThat(this.strategy.encodeURL("/url?a=b", "0")).isEqualTo("/url?a=b");
}
@Test
public void encodeURLExistingQueryExistingAliasStartDefaultAlias() {
// relaxed constraint as result /url?&y=z does not hurt anything (ideally should
// remove the &)
assertThat(this.strategy.encodeURL("/url?_s=1&y=z", "0"))
.doesNotContain("_s=0&_s=1");
}
@Test
public void encodeURLExistingQueryExistingAliasMiddleDefaultAlias() {
assertThat(this.strategy.encodeURL("/url?a=b&_s=1&y=z", "0"))
.isEqualTo("/url?a=b&y=z");
}
@Test
public void encodeURLExistingQueryExistingAliasEndDefaultAlias() {
assertThat(this.strategy.encodeURL("/url?a=b&_s=1", "0")).isEqualTo("/url?a=b");
}
@Test
public void encodeURLWithSameAlias() {
String url = String.format("/url?%s=1",
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME);
assertThat(this.strategy.encodeURL(url, "1")).isEqualTo(url);
}
@Test
public void encodeURLWithSameAliasOtherQueryParamsBefore() {
String url = String.format("/url?a=b&%s=1",
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME);
assertThat(this.strategy.encodeURL(url, "1")).isEqualTo(url);
}
@Test
public void encodeURLWithSameAliasOtherQueryParamsAfter() {
String url = String.format("/url?%s=1&a=b",
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME);
assertThat(this.strategy.encodeURL(url, "1")).isEqualTo(url);
}
@Test
public void encodeURLWithSameAliasOtherQueryParamsBeforeAndAfter() {
String url = String.format("/url?a=b&%s=1&c=d",
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME);
assertThat(this.strategy.encodeURL(url, "1")).isEqualTo(url);
}
@Test
public void encodeURLMaliciousAlias() {
assertThat(this.strategy.encodeURL("/url?a=b&_s=1",
"\"> <script>alert('hi')</script>")).isEqualTo(
"/url?a=b&_s=%22%3E+%3Cscript%3Ealert%28%27hi%27%29%3C%2Fscript%3E");
}
// --- getCurrentSessionAlias
@Test
public void getCurrentSessionAliasNull() {
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
@Test
public void getCurrentSessionAliasNullParamName() {
this.strategy.setSessionAliasParamName(null);
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "NOT USED");
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
// protect against malicious users
@Test
public void getCurrentSessionAliasContainsQuote() {
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here\"this");
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
@Test
public void getCurrentSessionAliasContainsSingleQuote() {
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here'this");
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
@Test
public void getCurrentSessionAliasContainsSpace() {
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here this");
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
@Test
public void getCurrentSessionAliasContainsLt() {
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here<this");
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
@Test
public void getCurrentSessionAliasContainsGt() {
this.strategy.setSessionAliasParamName(null);
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "here>this");
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
@Test
public void getCurrentSessionAliasTooLong() {
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME,
"012345678901234567890123456789012345678901234567890");
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
// We want some sort of length restrictions, but want to ensure some sort of length
// Technically no hard limit, but chose 50
@Test
public void getCurrentSessionAliasAllows50() {
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME,
"01234567890123456789012345678901234567890123456789");
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo("01234567890123456789012345678901234567890123456789");
}
@Test
public void getCurrentSession() {
String expectedAlias = "1";
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME,
expectedAlias);
assertThat(this.strategy.getCurrentSessionAlias(this.request))
.isEqualTo(expectedAlias);
}
// --- getNewSessionAlias
@Test
public void getNewSessionAliasNoSessions() {
assertThat(this.strategy.getNewSessionAlias(this.request))
.isEqualTo(CookieHttpSessionStrategy.DEFAULT_ALIAS);
}
@Test
public void getNewSessionAliasSingleSession() {
setSessionCookie("abc");
assertThat(this.strategy.getNewSessionAlias(this.request)).isEqualTo("1");
}
@Test
public void getNewSessionAlias2Sessions() {
setCookieWithNSessions(2);
assertThat(this.strategy.getNewSessionAlias(this.request)).isEqualTo("2");
}
@Test
public void getNewSessionAlias9Sessions() {
setCookieWithNSessions(9);
assertThat(this.strategy.getNewSessionAlias(this.request))
.isEqualToIgnoringCase("9");
}
@Test
public void getNewSessionAlias10Sessions() {
setCookieWithNSessions(10);
assertThat(this.strategy.getNewSessionAlias(this.request))
.isEqualToIgnoringCase("a");
}
@Test
public void getNewSessionAlias16Sessions() {
setCookieWithNSessions(16);
assertThat(this.strategy.getNewSessionAlias(this.request))
.isEqualToIgnoringCase("10");
}
@Test
public void getNewSessionAliasInvalidAlias() {
setSessionCookie("0 1 $ b");
assertThat(this.strategy.getNewSessionAlias(this.request))
.isEqualToIgnoringCase("1");
}
// --- getSessionIds
@Test
public void getSessionIdsNone() {
assertThat(this.strategy.getSessionIds(this.request)).isEmpty();
}
@Test
public void getSessionIdsSingle() {
String expectedId = "a";
setSessionCookie(expectedId);
Map<String, String> sessionIds = this.strategy.getSessionIds(this.request);
assertThat(sessionIds.size()).isEqualTo(1);
assertThat(sessionIds.get("0")).isEqualTo(expectedId);
}
@Test
public void getSessionIdsMulti() {
setSessionCookie("0 a 1 b");
Map<String, String> sessionIds = this.strategy.getSessionIds(this.request);
assertThat(sessionIds.size()).isEqualTo(2);
assertThat(sessionIds.get("0")).isEqualTo("a");
assertThat(sessionIds.get("1")).isEqualTo("b");
}
@Test
public void getSessionIdsMultiCustomDelimeter() {
this.strategy.setDeserializationDelimiter("_");
setSessionCookie("0_a_1_b");
Map<String, String> sessionIds = this.strategy.getSessionIds(this.request);
assertThat(sessionIds.size()).isEqualTo(2);
assertThat(sessionIds.get("0")).isEqualTo("a");
assertThat(sessionIds.get("1")).isEqualTo("b");
}
@Test
public void getSessionIdsMultiCustomDelimeterMigration() {
this.strategy.setDeserializationDelimiter("_ ");
this.strategy.setSerializationDelimiter("_");
// can parse the old way
setSessionCookie("0 a 1 b");
Map<String, String> sessionIds = this.strategy.getSessionIds(this.request);
assertThat(sessionIds.size()).isEqualTo(2);
assertThat(sessionIds.get("0")).isEqualTo("a");
assertThat(sessionIds.get("1")).isEqualTo("b");
// can parse the new way
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
setSessionCookie("0_a_1_b");
sessionIds = this.strategy.getSessionIds(this.request);
assertThat(sessionIds.size()).isEqualTo(2);
assertThat(sessionIds.get("0")).isEqualTo("a");
assertThat(sessionIds.get("1")).isEqualTo("b");
// writes the new way
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
Session existing = new MapSession();
setSessionCookie(existing.getId());
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "new");
this.strategy.onNewSession(this.session, this.request, this.response);
assertThat(getSessionId())
.isEqualTo("0_" + existing.getId() + "_new_" + this.session.getId());
}
@Test
public void getSessionIdsDangling() {
setSessionCookie("0 a 1 b noValue");
Map<String, String> sessionIds = this.strategy.getSessionIds(this.request);
assertThat(sessionIds.size()).isEqualTo(2);
assertThat(sessionIds.get("0")).isEqualTo("a");
assertThat(sessionIds.get("1")).isEqualTo("b");
}
// --- helper
@Test
public void createSessionCookieValue() {
assertThat(createSessionCookieValue(17)).isEqualToIgnoringCase(
"0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 a 10 b 11 c 12 d 13 e 14 f 15 10 16");
}
@Test
public void responseEncodeRedirectUrlWhereRedirectUrlDoesntContainAliasCurrentReqNoAlias() {
String url = "http://www.somehost.com/some/path";
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedRedirectUrl).isEqualTo(url);
}
@Test
public void responseEncodeRedirectUrlWhereRedirectUrlDoesntContainAliasCurrentReqHasAlias() {
String url = "http://www.somehost.com/some/path";
String alias = "1";
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias);
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedRedirectUrl).isEqualTo(String.format("%s?%s=%s", url,
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias));
}
@Test
public void responseEncodeRedirectUrlWhereRedirectUrlContainsAliasCurrentReqHasNoAlias() {
String url = String.format("http://www.somehost.com/some/path?%s=5",
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME);
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "4");
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedRedirectUrl).isEqualTo(url);
}
@Test
public void responseEncodeRedirectUrlWhereRedirectUrlDoesntContainAliasCurrentReqNoAliasWithOtherParams() {
String url = "http://www.somehost.com/some/path?a=b";
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedRedirectUrl).isEqualTo(url);
}
@Test
public void responseEncodeRedirectUrlWhereRedirectUrlDoesntContainAliasCurrentReqHasAliasWithOtherParams() {
String url = "http://www.somehost.com/some/path?a=b";
String alias = "1";
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias);
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedRedirectUrl).isEqualTo(String.format("%s&%s=%s", url,
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias));
}
@Test
public void responseEncodeRedirectUrlWhereRedirectUrlContainsAliasCurrentReqHasNoAliasWithOtherParams() {
String url = String.format("http://www.somehost.com/some/path?a=b&%s=5&c=d",
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME);
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "4");
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedRedirectUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedRedirectUrl).isEqualTo(url);
}
@Test
public void responseEncodeUrlWhereRedirectUrlDoesntContainAliasCurrentReqNoAlias() {
String url = "http://www.somehost.com/some/path";
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedUrl).isEqualTo(url);
}
@Test
public void responseEncodeUrlWhereRedirectUrlDoesntContainAliasCurrentReqHasAlias() {
String url = "http://www.somehost.com/some/path";
String alias = "1";
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias);
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedUrl).isEqualTo(String.format("%s?%s=%s", url,
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias));
}
@Test
public void responseEncodeUrlWhereRedirectUrlContainsAliasCurrentReqHasNoAlias() {
String url = String.format("http://www.somehost.com/some/path?%s=5",
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME);
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "4");
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedUrl).isEqualTo(url);
}
@Test
public void responseEncodeUrlWhereRedirectUrlDoesntContainAliasCurrentReqNoAliasWithOtherParams() {
String url = "http://www.somehost.com/some/path?a=b";
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedUrl).isEqualTo(url);
}
@Test
public void responseEncodeUrlWhereRedirectUrlDoesntContainAliasCurrentReqHasAliasWithOtherParams() {
String url = "http://www.somehost.com/some/path?a=b";
String alias = "1";
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias);
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedUrl).isEqualTo(String.format("%s&%s=%s", url,
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, alias));
}
@Test
public void responseEncodeUrlWhereRedirectUrlContainsAliasCurrentReqHasNoAliasWithOtherParams() {
String url = String.format("http://www.somehost.com/some/path?a=b&%s=5&c=d",
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME);
this.request.setParameter(
CookieHttpSessionStrategy.DEFAULT_SESSION_ALIAS_PARAM_NAME, "4");
HttpServletResponse wrappedResponse = this.strategy.wrapResponse(this.request,
this.response);
String encodedUrl = wrappedResponse.encodeRedirectURL(url);
assertThat(encodedUrl).isEqualTo(url);
}
private void setCookieWithNSessions(long size) {
setSessionCookie(createSessionCookieValue(size));
}
private String createSessionCookieValue(long size) {
StringBuilder sb = new StringBuilder();
@@ -720,18 +162,18 @@ public class CookieHttpSessionStrategyTests {
return sb.toString();
}
public void setCookieName(String cookieName) {
private void setCookieName(String cookieName) {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setCookieName(cookieName);
this.strategy.setCookieSerializer(cookieSerializer);
this.cookieName = cookieName;
}
public void setSessionCookie(String value) {
private void setSessionCookie(String value) {
this.request.setCookies(new Cookie(this.cookieName, base64Encode(value)));
}
public String getSessionId() {
private String getSessionId() {
return base64Decode(this.response.getCookie(this.cookieName).getValue());
}

View File

@@ -16,6 +16,8 @@
package org.springframework.session.web.http;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
@@ -26,6 +28,9 @@ import org.springframework.session.Session;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link HeaderHttpSessionStrategy}.
*/
public class HeaderSessionStrategyTests {
private MockHttpServletRequest request;
@@ -46,22 +51,22 @@ public class HeaderSessionStrategyTests {
@Test
public void getRequestedSessionIdNull() throws Exception {
assertThat(this.strategy.getRequestedSessionId(this.request)).isNull();
assertThat(this.strategy.getRequestedSessionIds(this.request)).isEmpty();
}
@Test
public void getRequestedSessionIdNotNull() throws Exception {
setSessionId(this.session.getId());
assertThat(this.strategy.getRequestedSessionId(this.request))
.isEqualTo(this.session.getId());
assertThat(this.strategy.getRequestedSessionIds(this.request))
.isEqualTo(Collections.singletonList(this.session.getId()));
}
@Test
public void getRequestedSessionIdNotNullCustomHeaderName() throws Exception {
setHeaderName("CUSTOM");
setSessionId(this.session.getId());
assertThat(this.strategy.getRequestedSessionId(this.request))
.isEqualTo(this.session.getId());
assertThat(this.strategy.getRequestedSessionIds(this.request))
.isEqualTo(Collections.singletonList(this.session.getId()));
}
@Test
@@ -116,16 +121,16 @@ public class HeaderSessionStrategyTests {
this.strategy.setHeaderName(null);
}
public void setHeaderName(String headerName) {
private void setHeaderName(String headerName) {
this.strategy.setHeaderName(headerName);
this.headerName = headerName;
}
public void setSessionId(String id) {
private void setSessionId(String id) {
this.request.addHeader(this.headerName, id);
}
public String getSessionId() {
private String getSessionId() {
return this.response.getHeader(this.headerName);
}

View File

@@ -60,12 +60,12 @@ import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -95,8 +95,7 @@ public class SessionRepositoryFilterTests {
public void setup() throws Exception {
this.sessions = new HashMap<>();
this.sessionRepository = new MapSessionRepository(this.sessions);
this.filter = new SessionRepositoryFilter<>(
this.sessionRepository);
this.filter = new SessionRepositoryFilter<>(this.sessionRepository);
setupRequest();
}
@@ -134,8 +133,7 @@ public class SessionRepositoryFilterTests {
session.setLastAccessedTime(Instant.EPOCH);
this.sessionRepository = spy(this.sessionRepository);
given(this.sessionRepository.createSession()).willReturn(session);
this.filter = new SessionRepositoryFilter<>(
this.sessionRepository);
this.filter = new SessionRepositoryFilter<>(this.sessionRepository);
doFilter(new DoInFilter() {
@Override
@@ -240,8 +238,7 @@ public class SessionRepositoryFilterTests {
@Test
public void doFilterServletContextExplicit() throws Exception {
final ServletContext expectedContext = new MockServletContext();
this.filter = new SessionRepositoryFilter<>(
this.sessionRepository);
this.filter = new SessionRepositoryFilter<>(this.sessionRepository);
this.filter.setServletContext(expectedContext);
doFilter(new DoInFilter() {
@@ -431,8 +428,7 @@ public class SessionRepositoryFilterTests {
return createSession();
}
};
this.filter = new SessionRepositoryFilter<>(
this.sessionRepository);
this.filter = new SessionRepositoryFilter<>(this.sessionRepository);
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
@@ -568,7 +564,7 @@ public class SessionRepositoryFilterTests {
ReflectionTestUtils.invokeMethod(wrappedRequest, "changeSessionId");
fail("Exected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -674,7 +670,7 @@ public class SessionRepositoryFilterTests {
sessionContext.getIds().nextElement();
fail("Expected Exception");
}
catch (NoSuchElementException success) {
catch (NoSuchElementException ignored) {
}
}
});
@@ -725,7 +721,7 @@ public class SessionRepositoryFilterTests {
session.invalidate();
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -742,7 +738,7 @@ public class SessionRepositoryFilterTests {
session.getCreationTime();
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -759,7 +755,7 @@ public class SessionRepositoryFilterTests {
session.getAttribute("attr");
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -776,7 +772,7 @@ public class SessionRepositoryFilterTests {
session.getValue("attr");
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -793,7 +789,7 @@ public class SessionRepositoryFilterTests {
session.getAttributeNames();
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -810,7 +806,7 @@ public class SessionRepositoryFilterTests {
session.getValueNames();
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -827,7 +823,7 @@ public class SessionRepositoryFilterTests {
session.setAttribute("a", "b");
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -844,7 +840,7 @@ public class SessionRepositoryFilterTests {
session.putValue("a", "b");
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -861,7 +857,7 @@ public class SessionRepositoryFilterTests {
session.removeAttribute("name");
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -878,7 +874,7 @@ public class SessionRepositoryFilterTests {
session.removeValue("name");
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -895,7 +891,7 @@ public class SessionRepositoryFilterTests {
session.isNew();
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -912,7 +908,7 @@ public class SessionRepositoryFilterTests {
session.getLastAccessedTime();
fail("Expected Exception");
}
catch (IllegalStateException success) {
catch (IllegalStateException ignored) {
}
}
});
@@ -1055,8 +1051,9 @@ public class SessionRepositoryFilterTests {
HttpServletResponse wrappedResponse) throws IOException {
String id = wrappedRequest.getSession().getId();
wrappedResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
assertThat(SessionRepositoryFilterTests.this.sessionRepository
.findById(id)).isNotNull();
assertThat(
SessionRepositoryFilterTests.this.sessionRepository.findById(id))
.isNotNull();
}
});
}
@@ -1070,8 +1067,9 @@ public class SessionRepositoryFilterTests {
String id = wrappedRequest.getSession().getId();
wrappedResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error");
assertThat(SessionRepositoryFilterTests.this.sessionRepository
.findById(id)).isNotNull();
assertThat(
SessionRepositoryFilterTests.this.sessionRepository.findById(id))
.isNotNull();
}
});
}
@@ -1084,8 +1082,9 @@ public class SessionRepositoryFilterTests {
HttpServletResponse wrappedResponse) throws IOException {
String id = wrappedRequest.getSession().getId();
wrappedResponse.sendRedirect("/");
assertThat(SessionRepositoryFilterTests.this.sessionRepository
.findById(id)).isNotNull();
assertThat(
SessionRepositoryFilterTests.this.sessionRepository.findById(id))
.isNotNull();
}
});
}
@@ -1098,8 +1097,9 @@ public class SessionRepositoryFilterTests {
HttpServletResponse wrappedResponse) throws IOException {
String id = wrappedRequest.getSession().getId();
wrappedResponse.flushBuffer();
assertThat(SessionRepositoryFilterTests.this.sessionRepository
.findById(id)).isNotNull();
assertThat(
SessionRepositoryFilterTests.this.sessionRepository.findById(id))
.isNotNull();
}
});
}
@@ -1112,8 +1112,9 @@ public class SessionRepositoryFilterTests {
HttpServletResponse wrappedResponse) throws IOException {
String id = wrappedRequest.getSession().getId();
wrappedResponse.getOutputStream().flush();
assertThat(SessionRepositoryFilterTests.this.sessionRepository
.findById(id)).isNotNull();
assertThat(
SessionRepositoryFilterTests.this.sessionRepository.findById(id))
.isNotNull();
}
});
}
@@ -1126,8 +1127,9 @@ public class SessionRepositoryFilterTests {
HttpServletResponse wrappedResponse) throws IOException {
String id = wrappedRequest.getSession().getId();
wrappedResponse.getOutputStream().close();
assertThat(SessionRepositoryFilterTests.this.sessionRepository
.findById(id)).isNotNull();
assertThat(
SessionRepositoryFilterTests.this.sessionRepository.findById(id))
.isNotNull();
}
});
}
@@ -1140,8 +1142,9 @@ public class SessionRepositoryFilterTests {
HttpServletResponse wrappedResponse) throws IOException {
String id = wrappedRequest.getSession().getId();
wrappedResponse.getWriter().flush();
assertThat(SessionRepositoryFilterTests.this.sessionRepository
.findById(id)).isNotNull();
assertThat(
SessionRepositoryFilterTests.this.sessionRepository.findById(id))
.isNotNull();
}
});
}
@@ -1154,20 +1157,28 @@ public class SessionRepositoryFilterTests {
HttpServletResponse wrappedResponse) throws IOException {
String id = wrappedRequest.getSession().getId();
wrappedResponse.getWriter().close();
assertThat(SessionRepositoryFilterTests.this.sessionRepository
.findById(id)).isNotNull();
assertThat(
SessionRepositoryFilterTests.this.sessionRepository.findById(id))
.isNotNull();
}
});
}
// --- MultiHttpSessionStrategyAdapter
// --- HttpSessionStrategy
@Test
public void doFilterAdapterGetRequestedSessionId() throws Exception {
SessionRepository<MapSession> sessionRepository = spy(
new MapSessionRepository(new ConcurrentHashMap<>()));
this.filter = new SessionRepositoryFilter<>(sessionRepository);
this.filter.setHttpSessionStrategy(this.strategy);
final String expectedId = "MultiHttpSessionStrategyAdapter-requested-id";
given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class)))
.willReturn(expectedId);
final String expectedId = "HttpSessionStrategy-requested-id";
given(this.strategy.getRequestedSessionIds(any(HttpServletRequest.class)))
.willReturn(Collections.singletonList(expectedId));
given(sessionRepository.findById(anyString()))
.willReturn(new MapSession(expectedId));
doFilter(new DoInFilter() {
@Override
@@ -1211,8 +1222,8 @@ public class SessionRepositoryFilterTests {
HttpServletRequest request = (HttpServletRequest) this.chain.getRequest();
String id = request.getSession().getId();
given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class)))
.willReturn(id);
given(this.strategy.getRequestedSessionIds(any(HttpServletRequest.class)))
.willReturn(Collections.singletonList(id));
setupRequest();
doFilter(new DoInFilter() {
@@ -1243,8 +1254,8 @@ public class SessionRepositoryFilterTests {
HttpServletRequest request = (HttpServletRequest) this.chain.getRequest();
String id = request.getSession().getId();
given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class)))
.willReturn(id);
given(this.strategy.getRequestedSessionIds(any(HttpServletRequest.class)))
.willReturn(Collections.singletonList(id));
doFilter(new DoInFilter() {
@Override
@@ -1340,52 +1351,7 @@ public class SessionRepositoryFilterTests {
@Test(expected = IllegalArgumentException.class)
public void setHttpSessionStrategyNull() {
this.filter.setHttpSessionStrategy((HttpSessionStrategy) null);
}
@Test(expected = IllegalArgumentException.class)
public void setMultiHttpSessionStrategyNull() {
this.filter.setHttpSessionStrategy((MultiHttpSessionStrategy) null);
}
@Test
public void getSessionFalseWithInvalidSessionIdShouldOnlyAskRepositoryOnce()
throws ServletException, IOException {
this.sessionRepository = spy(this.sessionRepository);
this.filter = new SessionRepositoryFilter<>(
this.sessionRepository);
final String nonExistantSessionId = "nonExistantSessionId";
setSessionCookie(nonExistantSessionId);
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
// Before first invocation
assertThat(SessionRepositoryFilterTests.this.request
.getAttribute(SessionRepositoryFilter.INVALID_SESSION_ID_ATTR))
.isNull();
// First call should go all the way through to the sessioRepository (it
// will not find the session)
HttpSession session = wrappedRequest.getSession(false);
verify(SessionRepositoryFilterTests.this.sessionRepository, times(1))
.findById(nonExistantSessionId);
assertThat(session).isNull();
assertThat(SessionRepositoryFilterTests.this.request
.getAttribute(SessionRepositoryFilter.INVALID_SESSION_ID_ATTR))
.isNotNull();
// Second call should not reach the sessionRepository
session = wrappedRequest.getSession(false);
verify(SessionRepositoryFilterTests.this.sessionRepository, times(1))
.findById(nonExistantSessionId); // still only called once
assertThat(session).isNull();
assertThat(SessionRepositoryFilterTests.this.request
.getAttribute(SessionRepositoryFilter.INVALID_SESSION_ID_ATTR))
.isNotNull();
}
});
this.filter.setHttpSessionStrategy(null);
}
// --- helper methods
@@ -1435,10 +1401,8 @@ public class SessionRepositoryFilterTests {
nameToCookie.put(cookie.getName(), cookie);
}
}
if (this.response.getCookies() != null) {
for (Cookie cookie : this.response.getCookies()) {
nameToCookie.put(cookie.getName(), cookie);
}
for (Cookie cookie : this.response.getCookies()) {
nameToCookie.put(cookie.getName(), cookie);
}
Cookie[] nextRequestCookies = new ArrayList<>(nameToCookie.values())
.toArray(new Cookie[0]);
@@ -1448,7 +1412,6 @@ public class SessionRepositoryFilterTests {
this.request.setCookies(nextRequestCookies);
}
@SuppressWarnings("serial")
private void doFilter(final DoInFilter doInFilter)
throws ServletException, IOException {
this.chain = new MockFilterChain(new HttpServlet() {
@@ -1456,7 +1419,7 @@ public class SessionRepositoryFilterTests {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
throws ServletException, IOException {
doInFilter.doFilter(request, response);
}
});
@@ -1471,21 +1434,25 @@ public class SessionRepositoryFilterTests {
return new String(Base64.getDecoder().decode(value));
}
abstract class DoInFilter {
private static class SessionRepositoryFilterDefaultOrder implements Ordered {
public int getOrder() {
return SessionRepositoryFilter.DEFAULT_ORDER;
}
}
private abstract class DoInFilter {
void doFilter(HttpServletRequest wrappedRequest,
HttpServletResponse wrappedResponse)
throws ServletException, IOException {
throws ServletException, IOException {
doFilter(wrappedRequest);
}
void doFilter(HttpServletRequest wrappedRequest) {
}
}
static class SessionRepositoryFilterDefaultOrder implements Ordered {
public int getOrder() {
return SessionRepositoryFilter.DEFAULT_ORDER;
}
}
}