]> source.dussan.org Git - vaadin-framework.git/commitdiff
Move reinitialize session to VaadinService (#9638) 11/11/2
authorLeif Åstrand <leif@vaadin.com>
Fri, 28 Sep 2012 11:58:37 +0000 (14:58 +0300)
committerVaadin Code Review <review@vaadin.com>
Fri, 28 Sep 2012 16:29:26 +0000 (16:29 +0000)
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

server/src/com/vaadin/server/VaadinService.java
server/src/com/vaadin/server/VaadinServiceSession.java
server/src/com/vaadin/server/VaadinServletSession.java
server/src/com/vaadin/server/WrappedHttpSession.java
server/src/com/vaadin/server/WrappedPortletSession.java
server/src/com/vaadin/server/WrappedSession.java
uitest/src/com/vaadin/tests/applicationcontext/ChangeSessionId.java

index 77a3018bb6e0ebe460cdd3c1d216c486cdfab6fd..add32bf57b3dacfa69588d81a67c52aedf66ceaa 100644 (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);
+            }
+        }
+
+    }
 }
index c581a1930cc9ccf6f44fa0d6b89ee405c357ccf7..67b224df70bb8791293aadefa74e8ede1698b10b 100644 (file)
@@ -225,6 +225,7 @@ public class VaadinServiceSession implements HttpSessionBindingListener,
         // closing
         // Notify the service
         service.fireSessionDestroy(this);
+        session = null;
     }
 
     /**
index 78f58d64fefa23bde032a480ec226a2e6041af1f..aa31a19c1bd44f2cb68e141f46e1b704b3ecce11 100644 (file)
 
 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.
      * 
index 1465588e0896accddc3e1298fe7b34fdb7463b64..e13a63635b65434e1464eb655ca57235aac2e763 100644 (file)
 
 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();
+    }
+
 }
index eb07eb38f68a4abd8b7e1d195ce70a1b27202566..03c1d7ba1f1eb17476aadf101755afd1f82571ea 100644 (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();
+    }
 }
index 3973c257c8be2c11c819f465abd01f086f7991c9..34443239c7401e19b78529eb1cdf68b592a5fd9b 100644 (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();
 }
index 72e0a215a729777dc6b575152a2630bbcfbe9d28..4495b343d05b1eb483256a43c5fa93a518f486ec 100644 (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 "