From a4a4d9e064f06ad4cdc2801db75955872a3acf45 Mon Sep 17 00:00:00 2001 From: Aleksi Hietanen Date: Thu, 13 Apr 2017 11:48:49 +0300 Subject: Use separate identifier for push connections Closes #8700 --- .../communication/AtmospherePushConnection.java | 12 +++++------ .../client/communication/MessageHandler.java | 19 ++++++++++++++++ .../main/java/com/vaadin/server/VaadinSession.java | 13 +++++++++++ .../vaadin/server/communication/PushHandler.java | 25 +++++++++++++++++++--- .../vaadin/server/communication/UIInitHandler.java | 15 +++++++++++++ .../com/vaadin/shared/ApplicationConstants.java | 9 +++++++- 6 files changed, 83 insertions(+), 10 deletions(-) diff --git a/client/src/main/java/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/main/java/com/vaadin/client/communication/AtmospherePushConnection.java index ba7fa39a7d..511a37b7e6 100644 --- a/client/src/main/java/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/main/java/com/vaadin/client/communication/AtmospherePushConnection.java @@ -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 @@ -526,7 +526,7 @@ public class AtmospherePushConnection implements PushConnection { JavaScriptObject config) /*-{ var self = this; - + config.url = uri; config.onOpen = $entry(function(response) { self.@com.vaadin.client.communication.AtmospherePushConnection::onOpen(*)(response); @@ -552,7 +552,7 @@ public class AtmospherePushConnection implements PushConnection { config.onClientTimeout = $entry(function(request) { self.@com.vaadin.client.communication.AtmospherePushConnection::onClientTimeout(*)(request); }); - + return $wnd.vaadinPush.atmosphere.subscribe(config); }-*/; diff --git a/client/src/main/java/com/vaadin/client/communication/MessageHandler.java b/client/src/main/java/com/vaadin/client/communication/MessageHandler.java index dcc3810a2d..c9cbf5737f 100644 --- a/client/src/main/java/com/vaadin/client/communication/MessageHandler.java +++ b/client/src/main/java/com/vaadin/client/communication/MessageHandler.java @@ -134,6 +134,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; @@ -350,6 +353,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")) { @@ -1687,6 +1696,16 @@ 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 + */ + 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 diff --git a/server/src/main/java/com/vaadin/server/VaadinSession.java b/server/src/main/java/com/vaadin/server/VaadinSession.java index 36692c00c2..46a11d3826 100644 --- a/server/src/main/java/com/vaadin/server/VaadinSession.java +++ b/server/src/main/java/com/vaadin/server/VaadinSession.java @@ -744,6 +744,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. @@ -1417,6 +1419,17 @@ 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 + */ + public String getPushId() { + assert hasLock(); + return pushId; + } + /** * Override default deserialization logic to account for transient * {@link #pendingAccessQueue}. diff --git a/server/src/main/java/com/vaadin/server/communication/PushHandler.java b/server/src/main/java/com/vaadin/server/communication/PushHandler.java index e65945d15c..6eeaa88520 100644 --- a/server/src/main/java/com/vaadin/server/communication/PushHandler.java +++ b/server/src/main/java/com/vaadin/server/communication/PushHandler.java @@ -90,10 +90,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 @@ -479,6 +479,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 * diff --git a/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java b/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java index c0c6850d32..f08f5fc45e 100644 --- a/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java @@ -287,6 +287,9 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { if (session.getConfiguration().isXsrfProtectionEnabled()) { writer.write(getSecurityKeyUIDL(session)); } + if (uI.getPushConfiguration().getPushMode().isEnabled()) { + writer.write(getPushIdUIDL(session)); + } new UidlWriter().write(uI, writer, false); writer.write("}"); @@ -310,6 +313,18 @@ public abstract class UIInitHandler extends SynchronizedRequestHandler { + seckey + "\","; } + /** + * Gets the push connection identifier as UIDL. + * + * @param session + * the vaadin session to which the security key belongs + * @return the push identifier UIDL + */ + private static String getPushIdUIDL(VaadinSession session) { + return "\"" + ApplicationConstants.UIDL_PUSH_ID + "\":\"" + + session.getPushId() + "\","; + } + private static final Logger getLogger() { return Logger.getLogger(UIInitHandler.class.getName()); } diff --git a/shared/src/main/java/com/vaadin/shared/ApplicationConstants.java b/shared/src/main/java/com/vaadin/shared/ApplicationConstants.java index 3a2b8b2b13..423e89645a 100644 --- a/shared/src/main/java/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/main/java/com/vaadin/shared/ApplicationConstants.java @@ -55,6 +55,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 @@ -80,7 +82,7 @@ public class ApplicationConstants implements Serializable { /** * Configuration parameter giving the (in some cases relative) URL to the * web application context root. - * + * * @since 8.0.3 */ public static final String CONTEXT_ROOT_URL = "contextRootUrl"; @@ -122,6 +124,11 @@ 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. + */ + public static final String PUSH_ID_PARAMETER = "v-pushId"; + /** * The name of the parameter used to transmit RPC invocations * -- cgit v1.2.3