diff --git a/spring-session/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java b/spring-session/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java index 4bcecc23..07567643 100644 --- a/spring-session/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java +++ b/spring-session/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java @@ -15,21 +15,27 @@ */ package org.springframework.session.web.http; -import org.springframework.core.annotation.Order; -import org.springframework.session.ExpiringSession; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; +import java.io.IOException; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; import javax.servlet.FilterChain; import javax.servlet.ServletContext; import javax.servlet.ServletException; -import javax.servlet.http.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionContext; -import java.io.IOException; -import java.util.Collections; -import java.util.Enumeration; -import java.util.NoSuchElementException; -import java.util.Set; +import org.springframework.core.annotation.Order; +import org.springframework.session.ExpiringSession; +import org.springframework.session.Session; +import org.springframework.session.SessionRepository; /** * Switches the {@link javax.servlet.http.HttpSession} implementation to be backed by a {@link org.springframework.session.Session}. @@ -176,6 +182,37 @@ public class SessionRepositoryFilter extends OncePerR } } + @SuppressWarnings("unused") + public String changeSessionId() { + HttpSession session = getSession(false); + + if(session == null) { + throw new IllegalStateException("Cannot change session ID. There is no session associated with this request."); + } + + // eagerly get session attributes in case implementation lazily loads them + Map attrs = new HashMap(); + Enumeration iAttrNames = session.getAttributeNames(); + while(iAttrNames.hasMoreElements()) { + String attrName = iAttrNames.nextElement(); + Object value = session.getAttribute(attrName); + + attrs.put(attrName, value); + } + + sessionRepository.delete(session.getId()); + currentSession = null; + + HttpSession newSession = getSession(); + newSession.setMaxInactiveInterval(session.getMaxInactiveInterval()); + for(Map.Entry attr : attrs.entrySet()) { + String attrName = attr.getKey(); + Object attrValue = attr.getValue(); + newSession.setAttribute(attrName, attrValue); + } + return newSession.getId(); + } + public boolean isRequestedSessionIdValid() { if(requestedSessionIdValid == null) { String sessionId = getRequestedSessionId(); diff --git a/spring-session/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java b/spring-session/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java index 61f2d446..53cfc3da 100644 --- a/spring-session/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java +++ b/spring-session/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java @@ -432,6 +432,60 @@ public class SessionRepositoryFilterTests { }); } + // gh-152 + @Test + public void doFilterChangeSessionId() throws Exception { + final String ATTR = "ATTRIBUTE"; + final String VALUE = "VALUE"; + + doFilter(new DoInFilter() { + @Override + public void doFilter(HttpServletRequest wrappedRequest) { + wrappedRequest.getSession().setAttribute(ATTR, VALUE); + } + }); + + final String originalSessionId = getSessionCookie().getValue(); + nextRequest(); + + // change the session id + doFilter(new DoInFilter() { + @Override + public void doFilter(HttpServletRequest wrappedRequest) { + ReflectionTestUtils.invokeMethod(wrappedRequest, "changeSessionId"); + } + }); + + // the old session was removed + final String changedSessionId = getSessionCookie().getValue(); + assertThat(originalSessionId).isNotEqualTo(changedSessionId); + assertThat(sessionRepository.getSession(originalSessionId)).isNull(); + + nextRequest(); + + // The attributes from previous session were migrated + doFilter(new DoInFilter() { + @Override + public void doFilter(HttpServletRequest wrappedRequest) { + assertThat(wrappedRequest.getSession().getAttribute(ATTR)).isEqualTo(VALUE); + } + }); + } + + @Test + public void doFilterChangeSessionIdNoSession() throws Exception { + // change the session id + doFilter(new DoInFilter() { + @Override + public void doFilter(HttpServletRequest wrappedRequest) { + try { + ReflectionTestUtils.invokeMethod(wrappedRequest, "changeSessionId"); + fail("Exected Exception"); + } catch(IllegalStateException success) {} + } + }); + } + // gh-142, gh-153 @Test public void doFilterIsRequestedValidSessionFalseInvalidId() throws Exception {