From 97fa55d3d447098bbf605054b1ccfa08a848dc3e Mon Sep 17 00:00:00 2001 From: Olli Tietäväinen Date: Thu, 10 Aug 2017 16:07:42 +0300 Subject: Use separate identifier for push connections (#9150) 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. --- .../main/java/com/vaadin/server/VaadinSession.java | 26 +++++++++++++++++----- .../vaadin/server/communication/PushHandler.java | 25 ++++++++++++++++++--- .../vaadin/server/communication/UIInitHandler.java | 18 +++++++++++++-- 3 files changed, 58 insertions(+), 11 deletions(-) (limited to 'server') diff --git a/server/src/main/java/com/vaadin/server/VaadinSession.java b/server/src/main/java/com/vaadin/server/VaadinSession.java index 7014a5f1f5..8cb833e68f 100644 --- a/server/src/main/java/com/vaadin/server/VaadinSession.java +++ b/server/src/main/java/com/vaadin/server/VaadinSession.java @@ -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}. 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 7cc41aeda3..2477a76d5c 100644 --- a/server/src/main/java/com/vaadin/server/communication/PushHandler.java +++ b/server/src/main/java/com/vaadin/server/communication/PushHandler.java @@ -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 * 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 aa167d137f..9ef63c3138 100644 --- a/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java +++ b/server/src/main/java/com/vaadin/server/communication/UIInitHandler.java @@ -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() { -- cgit v1.2.3