]> source.dussan.org Git - vaadin-framework.git/commitdiff
#6094 Add a way to switch session key
authorLeif Åstrand <leif@vaadin.com>
Fri, 19 Aug 2011 12:54:47 +0000 (12:54 +0000)
committerLeif Åstrand <leif@vaadin.com>
Fri, 19 Aug 2011 12:54:47 +0000 (12:54 +0000)
svn changeset:20519/svn branch:6.7

src/com/vaadin/terminal/gwt/server/PortletApplicationContext.java
src/com/vaadin/terminal/gwt/server/WebApplicationContext.java
tests/src/com/vaadin/tests/applicationcontext/ChangeSessionId.html [new file with mode: 0644]
tests/src/com/vaadin/tests/applicationcontext/ChangeSessionId.java [new file with mode: 0644]

index 49d40cbc6254287262c0764cdcfd9b14d24aaf27..79f223058821569d52be8b4dcb893b98092214ca 100644 (file)
@@ -95,6 +95,17 @@ public class PortletApplicationContext extends WebApplicationContext implements
         super.removeApplication(application);
     }
 
+    /**
+     * Reinitializing the session is not supported from portlets.
+     * 
+     * @see com.vaadin.terminal.gwt.server.WebApplicationContext#reinitializeSession()
+     */
+    @Override
+    public void reinitializeSession() {
+        throw new UnsupportedOperationException(
+                "Reinitializing the session is not supported from portlets");
+    }
+
     public void setPortletApplication(Portlet portlet, Application app) {
         portletToApplication.put(portlet, app);
     }
index dbb44d51d29e9447dc701b42d23dc92e63494b33..89b67738157288c478002da0a438262f75063b16 100644 (file)
@@ -5,8 +5,12 @@
 package com.vaadin.terminal.gwt.server;
 
 import java.io.File;
+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;
 
 import com.vaadin.Application;
@@ -26,6 +30,12 @@ import com.vaadin.Application;
 public class WebApplicationContext extends AbstractWebApplicationContext {
 
     protected transient HttpSession session;
+    private transient boolean reinitializingSession = false;
+
+    /**
+     * Stores a reference to the currentRequest. Null it not inside a request.
+     */
+    private transient Object currentRequest = null;
 
     /**
      * Creates a new Web Application Context.
@@ -35,6 +45,67 @@ public class WebApplicationContext extends AbstractWebApplicationContext {
 
     }
 
+    @Override
+    protected void startTransaction(Application application, Object request) {
+        currentRequest = request;
+        super.startTransaction(application, request);
+    }
+
+    @Override
+    protected void endTransaction(Application application, Object request) {
+        super.endTransaction(application, request);
+        currentRequest = null;
+    }
+
+    @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.
+     */
+    @SuppressWarnings("unchecked")
+    public void reinitializeSession() {
+
+        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 = ((HttpServletRequest) 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
+        session = newSession;
+    }
+
     /**
      * Gets the application context base directory.
      * 
diff --git a/tests/src/com/vaadin/tests/applicationcontext/ChangeSessionId.html b/tests/src/com/vaadin/tests/applicationcontext/ChangeSessionId.html
new file mode 100644 (file)
index 0000000..6d028f1
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://arturwin.office.itmill.com:8888/" />
+<title>ChangeSessionId</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">ChangeSessionId</td></tr>
+</thead><tbody>
+<tr>
+       <td>open</td>
+       <td>/run/com.vaadin.tests.applicationcontext.ChangeSessionId?restartApplication</td>
+       <td></td>
+</tr>
+<tr>
+       <td>click</td>
+       <td>vaadin=runcomvaadintestsapplicationcontextChangeSessionId::/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+       <td></td>
+</tr>
+<tr>
+       <td>click</td>
+       <td>vaadin=runcomvaadintestsapplicationcontextChangeSessionId::/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+       <td></td>
+</tr>
+<tr>
+       <td>assertText</td>
+       <td>vaadin=runcomvaadintestsapplicationcontextChangeSessionId::PID_SLog_row_1</td>
+       <td>2. Session id changed successfully from * to *</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/src/com/vaadin/tests/applicationcontext/ChangeSessionId.java b/tests/src/com/vaadin/tests/applicationcontext/ChangeSessionId.java
new file mode 100644 (file)
index 0000000..ddbbc49
--- /dev/null
@@ -0,0 +1,69 @@
+package com.vaadin.tests.applicationcontext;\r
+\r
+import com.vaadin.terminal.gwt.server.WebApplicationContext;\r
+import com.vaadin.tests.components.AbstractTestCase;\r
+import com.vaadin.tests.util.Log;\r
+import com.vaadin.ui.Button;\r
+import com.vaadin.ui.Button.ClickEvent;\r
+import com.vaadin.ui.Button.ClickListener;\r
+import com.vaadin.ui.Window;\r
+\r
+public class ChangeSessionId extends AbstractTestCase {\r
+\r
+    private Log log = new Log(5);\r
+    Button loginButton = new Button("Change session");\r
+    boolean requestSessionSwitch = false;\r
+\r
+    @Override\r
+    public void init() {\r
+        Window mainWindow = new Window("Sestest Application");\r
+        mainWindow.addComponent(log);\r
+        mainWindow.addComponent(loginButton);\r
+        mainWindow.addComponent(new Button("Show session id",\r
+                new Button.ClickListener() {\r
+\r
+                    public void buttonClick(ClickEvent event) {\r
+                        logSessionId();\r
+                    }\r
+                }));\r
+        setMainWindow(mainWindow);\r
+\r
+        loginButton.addListener(new ClickListener() {\r
+            public void buttonClick(ClickEvent event) {\r
+                WebApplicationContext context = ((WebApplicationContext) getContext());\r
+\r
+                String oldSessionId = context.getHttpSession().getId();\r
+                context.reinitializeSession();\r
+                String newSessionId = context.getHttpSession().getId();\r
+                if (oldSessionId.equals(newSessionId)) {\r
+                    log.log("FAILED! Both old and new session id is "\r
+                            + newSessionId);\r
+                } else {\r
+                    log.log("Session id changed successfully from "\r
+                            + oldSessionId + " to " + newSessionId);\r
+                }\r
+\r
+            }\r
+        });\r
+        logSessionId();\r
+    }\r
+\r
+    private void logSessionId() {\r
+        log.log("Session id: " + getSessionId());\r
+    }\r
+\r
+    protected String getSessionId() {\r
+        return ((WebApplicationContext) getContext()).getHttpSession().getId();\r
+    }\r
+\r
+    @Override\r
+    protected String getDescription() {\r
+        return "Tests that the session id can be changed to prevent session fixation attacks";\r
+    }\r
+\r
+    @Override\r
+    protected Integer getTicketNumber() {\r
+        return 6094;\r
+    }\r
+\r
+}
\ No newline at end of file