]> source.dussan.org Git - vaadin-framework.git/commitdiff
Use separate identifier for push connections (#9150)
authorOlli Tietäväinen <ollit@vaadin.com>
Thu, 10 Aug 2017 13:07:42 +0000 (16:07 +0300)
committerHenri Sara <henri.sara@gmail.com>
Thu, 10 Aug 2017 13:07:42 +0000 (16:07 +0300)
By using a separate id we can avoid sending the sessions
CSRF token as a GET parameter when initializing a push connection.

Cherry-picked from #8700 to the 7.7 branch.

client/src/main/java/com/vaadin/client/communication/AtmospherePushConnection.java
client/src/main/java/com/vaadin/client/communication/MessageHandler.java
server/src/main/java/com/vaadin/server/VaadinSession.java
server/src/main/java/com/vaadin/server/communication/PushHandler.java
server/src/main/java/com/vaadin/server/communication/UIInitHandler.java
shared/src/main/java/com/vaadin/shared/ApplicationConstants.java

index 34e1c5ff309087deaccd8eb11fe60fb2815f016b..a38bc7268bfee7f9ffffbc5ffb39d222797d6532 100644 (file)
@@ -207,10 +207,10 @@ public class AtmospherePushConnection implements PushConnection {
         String extraParams = UIConstants.UI_ID_PARAMETER + "="
                 + connection.getConfiguration().getUIId();
 
-        String csrfToken = connection.getMessageHandler().getCsrfToken();
-        if (!csrfToken.equals(ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE)) {
-            extraParams += "&" + ApplicationConstants.CSRF_TOKEN_PARAMETER + "="
-                    + csrfToken;
+        String pushId = connection.getMessageHandler().getPushId();
+        if (pushId != null) {
+            extraParams += "&" + ApplicationConstants.PUSH_ID_PARAMETER + "="
+                    + pushId;
         }
 
         // uri is needed to identify the right connection when closing
index 38b9a783e569abd79ec1ecacf9c2fb756691d34a..14cd31ec3211a54f57888e18243828bb35dbb1fd 100644 (file)
@@ -133,6 +133,9 @@ public class MessageHandler {
     // will hold the CSRF token once received
     private String csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE;
 
+    // holds the push identifier once received
+    private String pushId = null;
+
     /** Timer for automatic redirect to SessionExpiredURL */
     private Timer redirectTimer;
 
@@ -349,6 +352,12 @@ public class MessageHandler {
             csrfToken = json
                     .getString(ApplicationConstants.UIDL_SECURITY_TOKEN_ID);
         }
+
+        // Get push id if present
+        if (json.containsKey(ApplicationConstants.UIDL_PUSH_ID)) {
+            pushId = json.getString(ApplicationConstants.UIDL_PUSH_ID);
+        }
+
         getLogger().info(" * Handling resources from server");
 
         if (json.containsKey("resources")) {
@@ -361,7 +370,7 @@ public class MessageHandler {
             }
         }
         handleUIDLDuration
-                .logDuration(" * Handling resources from server completed", 10);
+        .logDuration(" * Handling resources from server completed", 10);
 
         getLogger().info(" * Handling type inheritance map from server");
 
@@ -489,7 +498,7 @@ public class MessageHandler {
                 if (json.containsKey("dd")) {
                     // response contains data for drag and drop service
                     VDragAndDropManager.get()
-                            .handleServerResponse(json.getValueMap("dd"));
+                    .handleServerResponse(json.getValueMap("dd"));
                 }
 
                 unregisterRemovedConnectors(
@@ -647,13 +656,13 @@ public class MessageHandler {
 
                     if (child instanceof ComponentConnector
                             && ((ComponentConnector) child)
-                                    .delegateCaptionHandling()) {
+                            .delegateCaptionHandling()) {
                         ServerConnector parent = child.getParent();
                         if (parent instanceof HasComponentsConnector) {
                             Profiler.enter(
                                     "HasComponentsConnector.updateCaption");
                             ((HasComponentsConnector) parent)
-                                    .updateCaption((ComponentConnector) child);
+                            .updateCaption((ComponentConnector) child);
                             Profiler.leave(
                                     "HasComponentsConnector.updateCaption");
                         }
@@ -732,7 +741,7 @@ public class MessageHandler {
                     throw new RuntimeException(
                             "Missing data needed to invoke @DelegateToWidget for "
                                     + component.getClass().getSimpleName(),
-                            e);
+                                    e);
                 }
             }
 
@@ -827,7 +836,7 @@ public class MessageHandler {
                 }
 
                 getLogger().info("* Unregistered " + detachedArray.length()
-                        + " connectors");
+                + " connectors");
                 Profiler.leave("unregisterRemovedConnectors");
             }
 
@@ -908,7 +917,7 @@ public class MessageHandler {
                 }
 
                 getLogger()
-                        .info(" * Passing UIDL to Vaadin 6 style connectors");
+                .info(" * Passing UIDL to Vaadin 6 style connectors");
                 // update paintables
                 for (int i = 0; i < length; i++) {
                     try {
@@ -935,14 +944,14 @@ public class MessageHandler {
                         } else if (legacyConnector == null) {
                             getLogger().severe(
                                     "Received update for " + uidl.getTag()
-                                            + ", but there is no such paintable ("
-                                            + connectorId + ") rendered.");
+                                    + ", but there is no such paintable ("
+                                    + connectorId + ") rendered.");
                         } else {
                             getLogger()
-                                    .severe("Server sent Vaadin 6 style updates for "
-                                            + Util.getConnectorString(
-                                                    legacyConnector)
-                                            + " but this is not a Vaadin 6 Paintable");
+                            .severe("Server sent Vaadin 6 style updates for "
+                                    + Util.getConnectorString(
+                                            legacyConnector)
+                                    + " but this is not a Vaadin 6 Paintable");
                         }
 
                     } catch (final Throwable e) {
@@ -1035,8 +1044,8 @@ public class MessageHandler {
 
                             if (connector instanceof HasJavaScriptConnectorHelper) {
                                 ((HasJavaScriptConnectorHelper) connector)
-                                        .getJavascriptConnectorHelper()
-                                        .setNativeState(jso);
+                                .getJavascriptConnectorHelper()
+                                .setNativeState(jso);
                             }
 
                             SharedState state = connector.getState();
@@ -1244,7 +1253,7 @@ public class MessageHandler {
                         newChildren.add(childConnector);
                         if (childConnector instanceof ComponentConnector) {
                             newComponents
-                                    .add((ComponentConnector) childConnector);
+                            .add((ComponentConnector) childConnector);
                         } else if (!(childConnector instanceof AbstractExtensionConnector)) {
                             throw new IllegalStateException(Util
                                     .getConnectorString(childConnector)
@@ -1419,7 +1428,7 @@ public class MessageHandler {
                 Profiler.enter(
                         prefix + "recursivelyDetach clear children and parent");
                 connector
-                        .setChildren(Collections.<ServerConnector> emptyList());
+                .setChildren(Collections.<ServerConnector> emptyList());
                 connector.setParent(null);
                 Profiler.leave(
                         prefix + "recursivelyDetach clear children and parent");
@@ -1465,7 +1474,7 @@ public class MessageHandler {
                     Profiler.enter("handleRpcInvocations");
 
                     getLogger()
-                            .info(" * Performing server to client RPC calls");
+                    .info(" * Performing server to client RPC calls");
 
                     JsonArray rpcCalls = Util
                             .jso2json(json.getJavaScriptObject("rpc"));
@@ -1693,6 +1702,17 @@ public class MessageHandler {
         return csrfToken;
     }
 
+    /**
+     * Gets the push connection identifier for this session. Used when
+     * establishing a push connection with the client.
+     *
+     * @return the push connection identifier string
+     * @since 7.7.11
+     */
+    public String getPushId() {
+        return pushId;
+    }
+
     /**
      * Checks whether state changes are currently being processed. Certain
      * operations are not allowed when the internal state of the application
index 7014a5f1f5e8ccfd98bd85e5597bf16923c14c9d..8cb833e68f5bc91bbb31ec6f61723690a5115f3a 100644 (file)
@@ -508,8 +508,8 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
     private void refreshLock() {
         assert lock == null || lock == service.getSessionLock(
                 session) : "Cannot change the lock from one instance to another";
-        assert hasLock(service, session);
-        lock = service.getSessionLock(session);
+                assert hasLock(service, session);
+                lock = service.getSessionLock(session);
     }
 
     public void setCommunicationManager(
@@ -747,6 +747,8 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
 
     private final String csrfToken = UUID.randomUUID().toString();
 
+    private final String pushId = UUID.randomUUID().toString();
+
     /**
      * Generate an id for the given Connector. Connectors must not call this
      * method more than once, the first time they need an id.
@@ -1008,12 +1010,12 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
                         getLogger().log(Level.SEVERE,
                                 "Exception while cleaning connector map for ui "
                                         + ui.getUIId(),
-                                e);
+                                        e);
                     } catch (AssertionError e) {
                         getLogger().log(Level.SEVERE,
                                 "Exception while cleaning connector map for ui "
                                         + ui.getUIId(),
-                                e);
+                                        e);
                     }
                 }
             }
@@ -1089,7 +1091,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
         }
         if (value != null && !type.isInstance(value)) {
             throw new IllegalArgumentException("value of type " + type.getName()
-                    + " expected but got " + value.getClass().getName());
+            + " expected but got " + value.getClass().getName());
         }
         setAttribute(type.getName(), value);
     }
@@ -1287,7 +1289,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
     protected void setState(State state) {
         assert hasLock();
         assert this.state.isValidChange(state) : "Invalid session state change "
-                + this.state + "->" + state;
+        + this.state + "->" + state;
 
         this.state = state;
     }
@@ -1422,6 +1424,18 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
         return csrfToken;
     }
 
+    /**
+     * Gets the push connection identifier for this session. Used when
+     * establishing a push connection with the client.
+     *
+     * @return the push connection identifier string
+     * @since 7.7.11
+     */
+    public String getPushId() {
+        assert hasLock();
+        return pushId;
+    }
+
     /**
      * Override default deserialization logic to account for transient
      * {@link #pendingAccessQueue}.
index 7cc41aeda3a218a2233212789401a52e4d7c5395..2477a76d5c8deeff95b97eb99fd4387786a88cb5 100644 (file)
@@ -91,10 +91,10 @@ public class PushHandler {
             }
 
             String requestToken = resource.getRequest()
-                    .getParameter(ApplicationConstants.CSRF_TOKEN_PARAMETER);
-            if (!VaadinService.isCsrfTokenValid(session, requestToken)) {
+                    .getParameter(ApplicationConstants.PUSH_ID_PARAMETER);
+            if (!isPushIdValid(session, requestToken)) {
                 getLogger().log(Level.WARNING,
-                        "Invalid CSRF token in new connection received from {0}",
+                        "Invalid identifier in new connection received from {0}",
                         resource.getRequest().getRemoteHost());
                 // Refresh on client side, create connection just for
                 // sending a message
@@ -472,6 +472,25 @@ public class PushHandler {
         return Logger.getLogger(PushHandler.class.getName());
     }
 
+    /**
+     * Checks whether a given push id matches the session's push id.
+     *
+     * @param session
+     *            the vaadin session for which the check should be done
+     * @param requestPushId
+     *            the push id provided in the request
+     * @return {@code true} if the id is valid, {@code false} otherwise
+     */
+    private static boolean isPushIdValid(VaadinSession session,
+            String requestPushId) {
+
+        String sessionPushId = session.getPushId();
+        if (requestPushId == null || !requestPushId.equals(sessionPushId)) {
+            return false;
+        }
+        return true;
+    }
+
     /**
      * Called when a new push connection is requested to be opened by the client
      *
index aa167d137f8e3ce2cb897246a641283fd7c66d5f..9ef63c31386db9ebe68898aa8641d3f65294e9e2 100644 (file)
@@ -220,7 +220,7 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler {
         session.addUI(ui);
         if (initException != null) {
             ui.getSession().getCommunicationManager()
-                    .handleConnectorRelatedException(ui, initException);
+            .handleConnectorRelatedException(ui, initException);
         }
         // Warn if the window can't be preserved
         if (embedId == null
@@ -288,6 +288,7 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler {
             if (session.getConfiguration().isXsrfProtectionEnabled()) {
                 writer.write(getSecurityKeyUIDL(session));
             }
+            writer.write(getPushIdUIDL(session));
             new UidlWriter().write(uI, writer, false);
             writer.write("}");
 
@@ -310,7 +311,20 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler {
         String seckey = session.getCsrfToken();
 
         return "\"" + ApplicationConstants.UIDL_SECURITY_TOKEN_ID + "\":\""
-                + seckey + "\",";
+        + seckey + "\",";
+    }
+
+    /**
+     * Gets the push connection identifier as UIDL.
+     *
+     * @param session
+     *            the vaadin session to which the security key belongs
+     * @return the push identifier UIDL
+     * @since 7.7.11
+     */
+    private static String getPushIdUIDL(VaadinSession session) {
+        return "\"" + ApplicationConstants.UIDL_PUSH_ID + "\":\""
+                + session.getPushId() + "\",";
     }
 
     private static final Logger getLogger() {
index 8ce9cef2d55b495a5b944978412680527e84c431..2a2d4c8ccbc7e2abbc2e0e77f3a05a69bffaa73d 100644 (file)
@@ -49,6 +49,8 @@ public class ApplicationConstants implements Serializable {
 
     public static final String UIDL_SECURITY_TOKEN_ID = "Vaadin-Security-Key";
 
+    public static final String UIDL_PUSH_ID = "Vaadin-Push-ID";
+
     @Deprecated
     public static final String UPDATE_VARIABLE_INTERFACE = "v";
     @Deprecated
@@ -108,6 +110,13 @@ public class ApplicationConstants implements Serializable {
      */
     public static final String CSRF_TOKEN_PARAMETER = "v-csrfToken";
 
+    /**
+     * Name of the parameter used to transmit the push connection identifier.
+     *
+     * @since 7.7.11
+     */
+    public static final String PUSH_ID_PARAMETER = "v-pushId";
+
     /**
      * The name of the parameter used to transmit RPC invocations
      *