String extraParams = UIConstants.UI_ID_PARAMETER + "=" | String extraParams = UIConstants.UI_ID_PARAMETER + "=" | ||||
+ connection.getConfiguration().getUIId(); | + 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 | // uri is needed to identify the right connection when closing | ||||
JavaScriptObject config) | JavaScriptObject config) | ||||
/*-{ | /*-{ | ||||
var self = this; | var self = this; | ||||
config.url = uri; | config.url = uri; | ||||
config.onOpen = $entry(function(response) { | config.onOpen = $entry(function(response) { | ||||
self.@com.vaadin.client.communication.AtmospherePushConnection::onOpen(*)(response); | self.@com.vaadin.client.communication.AtmospherePushConnection::onOpen(*)(response); | ||||
config.onClientTimeout = $entry(function(request) { | config.onClientTimeout = $entry(function(request) { | ||||
self.@com.vaadin.client.communication.AtmospherePushConnection::onClientTimeout(*)(request); | self.@com.vaadin.client.communication.AtmospherePushConnection::onClientTimeout(*)(request); | ||||
}); | }); | ||||
return $wnd.vaadinPush.atmosphere.subscribe(config); | return $wnd.vaadinPush.atmosphere.subscribe(config); | ||||
}-*/; | }-*/; | ||||
// will hold the CSRF token once received | // will hold the CSRF token once received | ||||
private String csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE; | private String csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE; | ||||
// holds the push identifier once received | |||||
private String pushId = null; | |||||
/** Timer for automatic redirect to SessionExpiredURL */ | /** Timer for automatic redirect to SessionExpiredURL */ | ||||
private Timer redirectTimer; | private Timer redirectTimer; | ||||
csrfToken = json | csrfToken = json | ||||
.getString(ApplicationConstants.UIDL_SECURITY_TOKEN_ID); | .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"); | getLogger().info(" * Handling resources from server"); | ||||
if (json.containsKey("resources")) { | if (json.containsKey("resources")) { | ||||
return csrfToken; | 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 | * Checks whether state changes are currently being processed. Certain | ||||
* operations are not allowed when the internal state of the application | * operations are not allowed when the internal state of the application |
*/ | */ | ||||
private final String csrfToken = UUID.randomUUID().toString(); | 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 | * Generate an id for the given Connector. Connectors must not call this | ||||
* method more than once, the first time they need an id. | * method more than once, the first time they need an id. | ||||
return csrfToken; | 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 | * Override default deserialization logic to account for transient | ||||
* {@link #pendingAccessQueue}. | * {@link #pendingAccessQueue}. |
} | } | ||||
String requestToken = resource.getRequest() | 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, | getLogger().log(Level.WARNING, | ||||
"Invalid CSRF token in new connection received from {0}", | |||||
"Invalid identifier in new connection received from {0}", | |||||
resource.getRequest().getRemoteHost()); | resource.getRequest().getRemoteHost()); | ||||
// Refresh on client side, create connection just for | // Refresh on client side, create connection just for | ||||
// sending a message | // sending a message | ||||
return Logger.getLogger(PushHandler.class.getName()); | 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 | * Called when a new push connection is requested to be opened by the client | ||||
* | * |
if (session.getConfiguration().isXsrfProtectionEnabled()) { | if (session.getConfiguration().isXsrfProtectionEnabled()) { | ||||
writer.write(getSecurityKeyUIDL(session)); | writer.write(getSecurityKeyUIDL(session)); | ||||
} | } | ||||
if (uI.getPushConfiguration().getPushMode().isEnabled()) { | |||||
writer.write(getPushIdUIDL(session)); | |||||
} | |||||
new UidlWriter().write(uI, writer, false); | new UidlWriter().write(uI, writer, false); | ||||
writer.write("}"); | writer.write("}"); | ||||
+ 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 | |||||
*/ | |||||
private static String getPushIdUIDL(VaadinSession session) { | |||||
return "\"" + ApplicationConstants.UIDL_PUSH_ID + "\":\"" | |||||
+ session.getPushId() + "\","; | |||||
} | |||||
private static final Logger getLogger() { | private static final Logger getLogger() { | ||||
return Logger.getLogger(UIInitHandler.class.getName()); | return Logger.getLogger(UIInitHandler.class.getName()); | ||||
} | } |
public static final String UIDL_SECURITY_TOKEN_ID = "Vaadin-Security-Key"; | public static final String UIDL_SECURITY_TOKEN_ID = "Vaadin-Security-Key"; | ||||
public static final String UIDL_PUSH_ID = "Vaadin-Push-ID"; | |||||
@Deprecated | @Deprecated | ||||
public static final String UPDATE_VARIABLE_INTERFACE = "v"; | public static final String UPDATE_VARIABLE_INTERFACE = "v"; | ||||
@Deprecated | @Deprecated | ||||
/** | /** | ||||
* Configuration parameter giving the (in some cases relative) URL to the | * Configuration parameter giving the (in some cases relative) URL to the | ||||
* web application context root. | * web application context root. | ||||
* | |||||
* | |||||
* @since 8.0.3 | * @since 8.0.3 | ||||
*/ | */ | ||||
public static final String CONTEXT_ROOT_URL = "contextRootUrl"; | public static final String CONTEXT_ROOT_URL = "contextRootUrl"; | ||||
*/ | */ | ||||
public static final String CSRF_TOKEN_PARAMETER = "v-csrfToken"; | 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 | * The name of the parameter used to transmit RPC invocations | ||||
* | * |