]> source.dussan.org Git - vaadin-framework.git/commitdiff
Double cookie submit pattern impl; fixes #2198
authorMarc Englund <marc.englund@itmill.com>
Mon, 10 Nov 2008 14:58:17 +0000 (14:58 +0000)
committerMarc Englund <marc.englund@itmill.com>
Mon, 10 Nov 2008 14:58:17 +0000 (14:58 +0000)
svn changeset:5855/svn branch:trunk

src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java
src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java
src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java

index 827c6353de90eb58e45e3f6980521bf059a56f9d..b09a9bc08c144c47c33a7d03d8d3bfc2c30eeba4 100755 (executable)
@@ -25,6 +25,7 @@ import com.google.gwt.json.client.JSONParser;
 import com.google.gwt.json.client.JSONString;
 import com.google.gwt.json.client.JSONValue;
 import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Cookies;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Element;
@@ -60,6 +61,8 @@ public class ApplicationConnection {
 
     public static final String VAR_BURST_SEPARATOR = "\u001d";
 
+    public static final String UIDL_SECURITY_COOKIE_NAME = "com.itmill.toolkit.seckey";
+
     private final HashMap resourcesMap = new HashMap();
 
     private static Console console;
@@ -276,6 +279,10 @@ public class ApplicationConnection {
             boolean forceSync) {
         startRequest();
 
+        // cookie double submission pattern
+        requestData = Cookies.getCookie(UIDL_SECURITY_COOKIE_NAME)
+                + VAR_BURST_SEPARATOR + requestData;
+
         console.log("Making UIDL Request with params: " + requestData);
         String uri = getAppUri() + "UIDL" + configuration.getPathInfo();
         if (repaintAll) {
@@ -637,7 +644,7 @@ public class ApplicationConnection {
                 }
 
                 if (html.length() != 0) {
-                    INotification n = new INotification(1000 * 60 * 45); // 45min
+                    INotification n = new INotification(1000 * 60 * 45); //45min
                     n.addEventListener(new NotificationRedirect(url));
                     n.show(html, INotification.CENTERED_TOP,
                             INotification.STYLE_SYSTEM);
index e7b61b094b33b08d1642542c9203f763ded7d71b..007843bef9fd18c71f8add7c5a5570c022ac1e8f 100644 (file)
@@ -16,6 +16,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.security.GeneralSecurityException;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -26,6 +27,7 @@ import java.util.Properties;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -42,6 +44,7 @@ import com.itmill.toolkit.terminal.ParameterHandler;
 import com.itmill.toolkit.terminal.Terminal;
 import com.itmill.toolkit.terminal.ThemeResource;
 import com.itmill.toolkit.terminal.URIHandler;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
 import com.itmill.toolkit.ui.Window;
 
 /**
@@ -526,6 +529,27 @@ public class ApplicationServlet extends HttpServlet {
                 throw new ServletException(ee);
             }
 
+        } catch (final GeneralSecurityException e) {
+            // TODO handle differently?
+            // Invalid security key, show session expired message for now
+            try {
+                Application.SystemMessages ci = getSystemMessages();
+                if (!UIDLrequest) {
+                    // 'plain' http req - e.g. browser reload;
+                    // just go ahead redirect the browser
+                    response.sendRedirect(ci.getSessionExpiredURL());
+                } else {
+                    // send uidl redirect
+                    criticalNotification(request, response, ci
+                            .getSessionExpiredCaption(), ci
+                            .getSessionExpiredMessage(), ci
+                            .getSessionExpiredURL());
+                }
+                request.getSession().invalidate();
+            } catch (SystemMessageException ee) {
+                throw new ServletException(ee);
+            }
+
         } catch (final Throwable e) {
             // if this was an UIDL request, response UIDL back to client
             if (UIDLrequest) {
@@ -748,6 +772,12 @@ public class ApplicationServlet extends HttpServlet {
             HttpServletResponse response, Window window, String themeName,
             Application application) throws IOException, MalformedURLException {
 
+        // Security: double cookie submission pattern
+        Cookie secCookie = new Cookie(
+                ApplicationConnection.UIDL_SECURITY_COOKIE_NAME, request
+                        .getSession().getId());
+        response.addCookie(secCookie);
+
         // e.g portlets only want a html fragment
         boolean fragment = (request.getAttribute(REQUEST_FRAGMENT) != null);
         if (fragment) {
index 0c7da3346623a6a8bed104e18b9e5e1cebedf745..56d4559f22905697e7a2f6cd0e2579b3dcb63c18 100644 (file)
@@ -14,6 +14,7 @@ import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.security.GeneralSecurityException;
 import java.text.DateFormatSymbols;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -216,7 +217,8 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
      */
     public void handleUidlRequest(HttpServletRequest request,
             HttpServletResponse response, ApplicationServlet applicationServlet)
-            throws IOException, ServletException {
+            throws IOException, ServletException,
+            InvalidUIDLSecurityKeyException {
 
         // repaint requested or session has timed out and new one is created
         boolean repaintAll = (request.getParameter(GET_PARAM_REPAINT_ALL) != null)
@@ -572,7 +574,7 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
      */
     private boolean handleVariables(HttpServletRequest request,
             HttpServletResponse response, Application application2,
-            Window window) throws IOException {
+            Window window) throws IOException, InvalidUIDLSecurityKeyException {
         boolean success = true;
 
         if (request.getContentLength() > 0) {
@@ -591,7 +593,13 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
             // Manage bursts one by one
             final String[] bursts = changes.split(VAR_BURST_SEPARATOR);
 
-            for (int bi = 0; bi < bursts.length; bi++) {
+            // check security key (==sessionid, double cookie submission
+            if (!request.getSession().getId().equals(bursts[0])) {
+                throw new InvalidUIDLSecurityKeyException(
+                        "Invalid UIDL security key");
+            }
+
+            for (int bi = 1; bi < bursts.length; bi++) {
 
                 // extract variables to two dim string array
                 final String[] tmp = bursts[bi].split(VAR_RECORD_SEPARATOR);
@@ -614,8 +622,7 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
                                 && variable[VAR_PID]
                                         .equals(nextVariable[VAR_PID])) {
                             // we have more than one value changes in row for
-                            // one
-                            // variable owner, collect em in HashMap
+                            // one variable owner, collect em in HashMap
                             m = new HashMap();
                             m.put(variable[VAR_NAME], convertVariableValue(
                                     variable[VAR_TYPE].charAt(0),
@@ -645,9 +652,8 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
                         try {
                             owner.changeVariables(request, m);
 
-                            // Special-case of closing browser-level
-                            // windows: track browser-windows currently open in
-                            // client
+                            // Special-case of closing browser-level windows:
+                            // track browser-windows currently open in client
                             if (owner instanceof Window
                                     && ((Window) owner).getParent() == null) {
                                 final Boolean close = (Boolean) m.get("close");
@@ -694,8 +700,7 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
                 // not interested in sending any UIDL changes back to client.
                 // Still we must clear component tree between bursts to ensure
                 // that no removed components are updated. The painting after
-                // the
-                // last burst is handled normally by the calling method.
+                // the last burst is handled normally by the calling method.
                 if (bi < bursts.length - 1) {
 
                     // We will be discarding all changes
@@ -1014,8 +1019,8 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
         if (logoutUrl == null) {
             logoutUrl = application.getURL().toString();
         }
-        // clients JS app is still running, send a special json file to
-        // tell client that application has quit and where to point browser now
+        // clients JS app is still running, send a special json file to tell
+        // client that application has quit and where to point browser now
         // Set the response type
         response.setContentType("application/json; charset=UTF-8");
         final ServletOutputStream out = response.getOutputStream();
@@ -1067,11 +1072,9 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
         final ArrayList resultset = new ArrayList(dirtyPaintabletSet);
 
         // The following algorithm removes any components that would be painted
-        // as
-        // a direct descendant of other components from the dirty components
-        // list.
-        // The result is that each component should be painted exactly once and
-        // any unmodified components will be painted as "cached=true".
+        // as a direct descendant of other components from the dirty components
+        // list. The result is that each component should be painted exactly
+        // once and any unmodified components will be painted as "cached=true".
 
         for (final Iterator i = dirtyPaintabletSet.iterator(); i.hasNext();) {
             final Paintable p = (Paintable) i.next();
@@ -1299,4 +1302,12 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
         return false;
     }
 
+    private class InvalidUIDLSecurityKeyException extends
+            GeneralSecurityException {
+
+        InvalidUIDLSecurityKeyException(String message) {
+            super(message);
+        }
+
+    }
 }