currentSession saved on HttpServletRequest attribute

Previously, if the following happened:

* New Session Created
* Exception thrown
* Exception processed by error handler within Servlet
* Error Handler used a session

The result would be two sessions were created. This means the
data from the first session was also lost. This happend
because ERROR dispatch is a separate Filter invocation where
the request is no longer wrapped.

This commit ensures that currentSession is saved on a
HttpServletRequest attribute so that the ERROR dispatch sees
that a session was already created.

Fixes: gh-229
This commit is contained in:
Rob Winch
2015-07-27 16:52:33 -05:00
parent 8929e85fb1
commit 3d93f2cf56
2 changed files with 49 additions and 7 deletions

View File

@@ -58,6 +58,7 @@ import org.springframework.session.SessionRepository;
* @since 1.0
* @author Rob Winch
*/
@SuppressWarnings("deprecation")
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerRequestFilter {
public static final String SESSION_REPOSITORY_ATTR = SessionRepository.class.getName();
@@ -161,7 +162,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
* @since 1.0
*/
private final class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {
private HttpSessionWrapper currentSession;
private final String CURRENT_SESSION_ATTR = HttpServletRequestWrapper.class.getName();
private Boolean requestedSessionIdValid;
private boolean requestedSessionInvalidated;
private final HttpServletResponse response;
@@ -177,7 +178,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
* Uses the HttpSessionStrategy to write the session id tot he response and persist the Session.
*/
private void commitSession() {
HttpSessionWrapper wrappedSession = currentSession;
HttpSessionWrapper wrappedSession = getCurrentSession();
if(wrappedSession == null) {
if(isInvalidateClientSession()) {
httpSessionStrategy.onInvalidateSession(this, response);
@@ -191,6 +192,19 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
}
}
@SuppressWarnings("unchecked")
private HttpSessionWrapper getCurrentSession() {
return (HttpSessionWrapper) getAttribute(CURRENT_SESSION_ATTR);
}
private void setCurrentSession(HttpSessionWrapper currentSession) {
if(currentSession == null) {
removeAttribute(CURRENT_SESSION_ATTR);
} else {
setAttribute(CURRENT_SESSION_ATTR, currentSession);
}
}
@SuppressWarnings({ "unused", "unchecked" })
public String changeSessionId() {
HttpSession session = getSession(false);
@@ -210,8 +224,8 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
}
sessionRepository.delete(session.getId());
HttpSessionWrapper original = currentSession;
currentSession = null;
HttpSessionWrapper original = getCurrentSession();
setCurrentSession(null);
HttpSession newSession = getSession();
original.session = ((HttpSessionWrapper)newSession).session;
@@ -243,11 +257,12 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
}
private boolean isInvalidateClientSession() {
return currentSession == null && requestedSessionInvalidated;
return getCurrentSession() == null && requestedSessionInvalidated;
}
@Override
public HttpSession getSession(boolean create) {
HttpSessionWrapper currentSession = getCurrentSession();
if(currentSession != null) {
return currentSession;
}
@@ -258,6 +273,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
this.requestedSessionIdValid = true;
currentSession = new HttpSessionWrapper(session, getServletContext());
currentSession.setNew(false);
setCurrentSession(currentSession);
return currentSession;
}
}
@@ -266,6 +282,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
}
S session = sessionRepository.createSession();
currentSession = new HttpSessionWrapper(session, getServletContext());
setCurrentSession(currentSession);
return currentSession;
}
@@ -377,7 +394,7 @@ public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerR
checkState();
this.invalidated = true;
requestedSessionInvalidated = true;
currentSession = null;
setCurrentSession(null);
sessionRepository.delete(getId());
}

View File

@@ -67,6 +67,8 @@ public class SessionRepositoryFilterTests {
@Mock
private HttpSessionStrategy strategy;
private Map<String, ExpiringSession> sessions;
private SessionRepository<ExpiringSession> sessionRepository;
private SessionRepositoryFilter<ExpiringSession> filter;
@@ -79,7 +81,8 @@ public class SessionRepositoryFilterTests {
@Before
public void setup() throws Exception {
sessionRepository = new MapSessionRepository();
sessions = new HashMap<String, ExpiringSession>();
sessionRepository = new MapSessionRepository(sessions);
filter = new SessionRepositoryFilter<ExpiringSession>(sessionRepository);
setupRequest();
}
@@ -558,6 +561,28 @@ public class SessionRepositoryFilterTests {
});
}
// gh-229
@Test
public void doFilterGetSessionGetSessionOnError() throws Exception {
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
wrappedRequest.getSession().setAttribute("a", "b");
}
});
// reuse the same request similar to processing an ERROR dispatch
doFilter(new DoInFilter() {
@Override
public void doFilter(HttpServletRequest wrappedRequest) {
assertThat(wrappedRequest.getSession(false)).isNotNull();
}
});
assertThat(this.sessions.size()).isEqualTo(1);
}
@Test
public void doFilterCookieSecuritySettings() throws Exception {
request.setSecure(true);