Browse Source

Move reinitialize session to VaadinService (#9638)

This change adds reinitializeSession as a static method in
VaadinService. The method is static because it affects the sessions of
all VaadinService instances that are using the underlying session.

Change-Id: Ia37567cb00e1f95aec344451299c99cb279a7275
tags/7.0.0.beta3
Leif Åstrand 11 years ago
parent
commit
ca59c93fb4

+ 63
- 0
server/src/com/vaadin/server/VaadinService.java View File

@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.ServiceLoader;
@@ -49,6 +50,9 @@ import com.vaadin.util.ReflectTools;
* @since 7.0
*/
public abstract class VaadinService implements Serializable {
private static final String REINITIALIZING_SESSION_MARKER = VaadinService.class
.getName() + ".reinitializing";

private static final Method SESSION_INIT_METHOD = ReflectTools.findMethod(
SessionInitListener.class, "sessionInit", SessionInitEvent.class);

@@ -271,6 +275,11 @@ public abstract class VaadinService implements Serializable {
}

public void fireSessionDestroy(VaadinServiceSession vaadinSession) {
// Ignore if the session is being moved to a different backing session
if (vaadinSession.getAttribute(REINITIALIZING_SESSION_MARKER) == Boolean.TRUE) {
return;
}

for (UI ui : new ArrayList<UI>(vaadinSession.getUIs())) {
vaadinSession.cleanupUI(ui);
}
@@ -619,4 +628,58 @@ public abstract class VaadinService implements Serializable {
public boolean preserveUIOnRefresh(UIProvider provider, UICreateEvent event) {
return provider.isPreservedOnRefresh(event);
}

/**
* Discards the current session and creates a new session with the same
* contents. The purpose of this is to introduce a new session key in order
* to avoid session fixation attacks.
* <p>
* Please note that this method makes certain assumptions about how data is
* stored in the underlying session and may thus not be compatible with some
* environments.
*
* @param request
* The Vaadin request for which the session should be
* reinitialized
*/
public static void reinitializeSession(VaadinRequest request) {
WrappedSession oldSession = request.getWrappedSession();

// Stores all attributes (security key, reference to this context
// instance) so they can be added to the new session
HashMap<String, Object> attrs = new HashMap<String, Object>();
for (String name : oldSession.getAttributeNames()) {
Object value = oldSession.getAttribute(name);
if (value instanceof VaadinServiceSession) {
// set flag to avoid cleanup
VaadinServiceSession serviceSession = (VaadinServiceSession) value;
serviceSession.setAttribute(REINITIALIZING_SESSION_MARKER,
Boolean.TRUE);
}
attrs.put(name, value);
}

// Invalidate the current session
oldSession.invalidate();

// Create a new session
WrappedSession newSession = request.getWrappedSession();

// Restores all attributes (security key, reference to this context
// instance)
for (String name : attrs.keySet()) {
Object value = attrs.get(name);
newSession.setAttribute(name, value);

// Ensure VaadinServiceSession knows where it's stored
if (value instanceof VaadinServiceSession) {
VaadinServiceSession serviceSession = (VaadinServiceSession) value;
serviceSession.storeInSession(serviceSession.getService(),
newSession);
serviceSession
.setAttribute(REINITIALIZING_SESSION_MARKER, null);
}
}

}
}

+ 1
- 0
server/src/com/vaadin/server/VaadinServiceSession.java View File

@@ -225,6 +225,7 @@ public class VaadinServiceSession implements HttpSessionBindingListener,
// closing
// Notify the service
service.fireSessionDestroy(this);
session = null;
}

/**

+ 0
- 61
server/src/com/vaadin/server/VaadinServletSession.java View File

@@ -16,12 +16,7 @@

package com.vaadin.server;

import java.util.Enumeration;
import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

/**
@@ -39,8 +34,6 @@ import javax.servlet.http.HttpSessionBindingListener;
@SuppressWarnings("serial")
public class VaadinServletSession extends VaadinServiceSession {

private transient boolean reinitializingSession = false;

/**
* Create a servlet service session for the given servlet service
*
@@ -51,60 +44,6 @@ public class VaadinServletSession extends VaadinServiceSession {
super(service);
}

@Override
public void valueUnbound(HttpSessionBindingEvent event) {
if (!reinitializingSession) {
// Avoid closing the application if we are only reinitializing the
// session. Closing the application would cause the state to be lost
// and a new application to be created, which is not what we want.
super.valueUnbound(event);
}
}

/**
* Discards the current session and creates a new session with the same
* contents. The purpose of this is to introduce a new session key in order
* to avoid session fixation attacks.
*/
public void reinitializeSession() {
HttpServletRequest currentRequest = VaadinServletService
.getCurrentServletRequest();
if (currentRequest == null) {
throw new IllegalStateException(
"Can not reinitialize session outside normal request handling.");
}

HttpSession oldSession = getHttpSession();

// Stores all attributes (security key, reference to this context
// instance) so they can be added to the new session
HashMap<String, Object> attrs = new HashMap<String, Object>();
for (Enumeration<String> e = oldSession.getAttributeNames(); e
.hasMoreElements();) {
String name = e.nextElement();
attrs.put(name, oldSession.getAttribute(name));
}

// Invalidate the current session, set flag to avoid call to
// valueUnbound
reinitializingSession = true;
oldSession.invalidate();
reinitializingSession = false;

// Create a new session
HttpSession newSession = currentRequest.getSession();

// Restores all attributes (security key, reference to this context
// instance)
for (String name : attrs.keySet()) {
newSession.setAttribute(name, attrs.get(name));
}

// Update the "current session" variable
storeInSession(VaadinService.getCurrent(), new WrappedHttpSession(
newSession));
}

/**
* Gets the http-session application is running in.
*

+ 25
- 0
server/src/com/vaadin/server/WrappedHttpSession.java View File

@@ -16,6 +16,11 @@

package com.vaadin.server;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpSession;

/**
@@ -63,4 +68,24 @@ public class WrappedHttpSession implements WrappedSession {
return session;
}

@Override
public Set<String> getAttributeNames() {
Enumeration<String> attributeNames = session.getAttributeNames();
return enumerationToSet(attributeNames);
}

// Helper shared with WrappedPortletSession
static <T> Set<T> enumerationToSet(Enumeration<T> values) {
HashSet<T> set = new HashSet<T>();
while (values.hasMoreElements()) {
set.add(values.nextElement());
}
return Collections.unmodifiableSet(set);
}

@Override
public void invalidate() {
session.invalidate();
}

}

+ 12
- 0
server/src/com/vaadin/server/WrappedPortletSession.java View File

@@ -16,6 +16,8 @@

package com.vaadin.server;

import java.util.Set;

import javax.portlet.PortletSession;

/**
@@ -62,4 +64,14 @@ public class WrappedPortletSession implements WrappedSession {
public PortletSession getPortletSession() {
return session;
}

@Override
public Set<String> getAttributeNames() {
return WrappedHttpSession.enumerationToSet(session.getAttributeNames());
}

@Override
public void invalidate() {
session.invalidate();
}
}

+ 20
- 0
server/src/com/vaadin/server/WrappedSession.java View File

@@ -16,6 +16,8 @@

package com.vaadin.server;

import java.util.Set;

import javax.portlet.PortletSession;
import javax.servlet.http.HttpSession;

@@ -66,4 +68,22 @@ public interface WrappedSession {
* @see javax.portlet.PortletSession#setAttribute(String, Object)
*/
public void setAttribute(String name, Object value);

/**
* Gets the current set of attribute names stored in this session.
*
* @return an unmodifiable set of the current attribute names
*
* @see HttpSession#getAttributeNames()
* @see PortletSession#getAttributeNames()
*/
public Set<String> getAttributeNames();

/**
* Invalidates this session then unbinds any objects bound to it.
*
* @see HttpSession#invalidate()
* @see PortletSession#invalidate()
*/
public void invalidate();
}

+ 3
- 1
uitest/src/com/vaadin/tests/applicationcontext/ChangeSessionId.java View File

@@ -1,5 +1,6 @@
package com.vaadin.tests.applicationcontext;

import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServletSession;
import com.vaadin.tests.components.AbstractTestCase;
import com.vaadin.tests.util.Log;
@@ -35,7 +36,8 @@ public class ChangeSessionId extends AbstractTestCase {
VaadinServletSession context = ((VaadinServletSession) getContext());

String oldSessionId = context.getHttpSession().getId();
context.reinitializeSession();
context.getService().reinitializeSession(
VaadinService.getCurrentRequest());
String newSessionId = context.getHttpSession().getId();
if (oldSessionId.equals(newSessionId)) {
log.log("FAILED! Both old and new session id is "

Loading…
Cancel
Save