diff options
author | Bogdan Udrescu <bogdan@vaadin.com> | 2014-07-09 18:40:26 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2014-07-15 08:50:38 +0000 |
commit | df13b061f2f6ba10beae64d9b358c0365736370e (patch) | |
tree | 0a2800b1e383f3f7fb648ea5ec9ec9512e54906d | |
parent | 9696e6c3e7e952b66ac3f5c9ddc3dfca4233451e (diff) | |
download | vaadin-framework-df13b061f2f6ba10beae64d9b358c0365736370e.tar.gz vaadin-framework-df13b061f2f6ba10beae64d9b358c0365736370e.zip |
Remove csrfToken if disable-xsrf-protection is true (#14111)
If the server sends no token and the client value remains "init" then
it's not sent back to the server.
Change-Id: I74fc470c5c22d57c4a48eab3e4476ae4cc2dd242
15 files changed, 903 insertions, 117 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 6bbca98042..6abcdac487 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -111,14 +111,14 @@ import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; * This is the client side communication "engine", managing client-server * communication with its server side counterpart * com.vaadin.server.VaadinService. - * + * * Client-side connectors receive updates from the corresponding server-side * connector (typically component) as state updates or RPC calls. The connector * has the possibility to communicate back with its server side counter part * through RPC calls. - * + * * TODO document better - * + * * Entry point classes (widgetsets) define <code>onModuleLoad()</code>. */ public class ApplicationConnection implements HasHandlers { @@ -150,12 +150,12 @@ public class ApplicationConnection implements HasHandlers { * A string that, if found in a non-JSON response to a UIDL request, will * cause the browser to refresh the page. If followed by a colon, optional * whitespace, and a URI, causes the browser to synchronously load the URI. - * + * * <p> * This allows, for instance, a servlet filter to redirect the application * to a custom login page when the session expires. For example: * </p> - * + * * <pre> * if (sessionExpired) { * response.setHeader("Content-Type", "text/html"); @@ -168,7 +168,7 @@ public class ApplicationConnection implements HasHandlers { public static final String UIDL_REFRESH_TOKEN = "Vaadin-Refresh"; // will hold the CSRF token once received - private String csrfToken = "init"; + private String csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE; private final HashMap<String, String> resourcesMap = new HashMap<String, String>(); @@ -346,7 +346,7 @@ public class ApplicationConnection implements HasHandlers { /** * Event triggered when a XHR request has finished with the status code of * the response. - * + * * Useful for handlers observing network failures like online/off-line * monitors. */ @@ -402,12 +402,12 @@ public class ApplicationConnection implements HasHandlers { /** * Event triggered when a application is stopped by calling * {@link ApplicationConnection#setApplicationRunning(false)}. - * + * * To listen for the event add a {@link ApplicationStoppedHandler} by * invoking * {@link ApplicationConnection#addHandler(ApplicationConnection.ApplicationStoppedEvent.Type, ApplicationStoppedHandler)} * to the {@link ApplicationConnection} - * + * * @since 7.1.8 * @author Vaadin Ltd */ @@ -434,7 +434,7 @@ public class ApplicationConnection implements HasHandlers { /** * Called when a communication error has occurred. Returning * <code>true</code> from this method suppresses error handling. - * + * * @param details * A string describing the error. * @param statusCode @@ -449,7 +449,7 @@ public class ApplicationConnection implements HasHandlers { * A listener for listening to application stopped events. The listener can * be added to a {@link ApplicationConnection} by invoking * {@link ApplicationConnection#addHandler(ApplicationStoppedEvent.Type, ApplicationStoppedHandler)} - * + * * @since 7.1.8 * @author Vaadin Ltd */ @@ -459,7 +459,7 @@ public class ApplicationConnection implements HasHandlers { * Triggered when the {@link ApplicationConnection} marks a previously * running application as stopped by invoking * {@link ApplicationConnection#setApplicationRunning(false)} - * + * * @param event * the event triggered by the {@link ApplicationConnection} */ @@ -570,7 +570,7 @@ public class ApplicationConnection implements HasHandlers { * called once this application has started (first response received) or * failed to start. This ensures that the applications are started in order, * to avoid session-id problems. - * + * */ public void start() { String jsonText = configuration.getUIDL(); @@ -671,7 +671,7 @@ public class ApplicationConnection implements HasHandlers { * <li><code>vaadin.postRequestHooks</code> is a map of functions which gets * called after each XHR made by vaadin application. Note, that it is * attaching js functions responsibility to create the variable like this: - * + * * <code><pre> * if(!vaadin.postRequestHooks) {vaadin.postRequestHooks = new Object();} * postRequestHooks.myHook = function(appId) { @@ -682,7 +682,7 @@ public class ApplicationConnection implements HasHandlers { * </pre></code> First parameter passed to these functions is the identifier * of Vaadin application that made the request. * </ul> - * + * * TODO make this multi-app aware */ private native void initializeClientHooks() @@ -713,7 +713,7 @@ public class ApplicationConnection implements HasHandlers { /** * Runs possibly registered client side post request hooks. This is expected * to be run after each uidl request made by Vaadin application. - * + * * @param appId */ private static native void runPostRequestHooks(String appId) @@ -733,7 +733,7 @@ public class ApplicationConnection implements HasHandlers { /** * If on Liferay and logged in, ask the client side session management * JavaScript to extend the session duration. - * + * * Otherwise, Liferay client side JavaScript will explicitly expire the * session even though the server side considers the session to be active. * See ticket #8305 for more information. @@ -752,7 +752,7 @@ public class ApplicationConnection implements HasHandlers { /** * Indicates whether or not there are currently active UIDL requests. Used * internally to sequence requests properly, seldom needed in Widgets. - * + * * @return true if there are active requests */ public boolean hasActiveRequest() { @@ -772,7 +772,7 @@ public class ApplicationConnection implements HasHandlers { /** * Requests an analyze of layouts, to find inconsistencies. Exclusively used * for debugging during development. - * + * * @deprecated as of 7.1. Replaced by {@link UIConnector#analyzeLayouts()} */ @Deprecated @@ -784,7 +784,7 @@ public class ApplicationConnection implements HasHandlers { * Sends a request to the server to print details to console that will help * the developer to locate the corresponding server-side connector in the * source code. - * + * * @param serverConnector * @deprecated as of 7.1. Replaced by * {@link UIConnector#showServerDebugInfo(ServerConnector)} @@ -796,7 +796,7 @@ public class ApplicationConnection implements HasHandlers { /** * Makes an UIDL request to the server. - * + * * @param reqInvocations * Data containing RPC invocations and all related information. * @param extraParams @@ -810,8 +810,10 @@ public class ApplicationConnection implements HasHandlers { startRequest(); JSONObject payload = new JSONObject(); - payload.put(ApplicationConstants.CSRF_TOKEN, new JSONString( - getCsrfToken())); + if (!getCsrfToken().equals(ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE)) { + payload.put(ApplicationConstants.CSRF_TOKEN, new JSONString( + getCsrfToken())); + } payload.put(ApplicationConstants.RPC_INVOCATIONS, reqInvocations); payload.put(ApplicationConstants.SERVER_SYNC_ID, new JSONNumber( lastSeenServerSyncId)); @@ -833,7 +835,7 @@ public class ApplicationConnection implements HasHandlers { /** * Sends an asynchronous or synchronous UIDL request to the server using the * given URI. - * + * * @param uri * The URI to use for the request. May includes GET parameters * @param payload @@ -971,7 +973,7 @@ public class ApplicationConnection implements HasHandlers { /** * Handles received UIDL JSON text, parsing it, and passing it on to the * appropriate handlers, while logging timing information. - * + * * @param jsonText * @param statusCode */ @@ -999,7 +1001,7 @@ public class ApplicationConnection implements HasHandlers { /** * Sends an asynchronous UIDL request to the server using the given URI. - * + * * @param uri * The URI to use for the request. May includes GET parameters * @param payload @@ -1134,7 +1136,7 @@ public class ApplicationConnection implements HasHandlers { /** * Checks whether or not the CSS is loaded. By default checks the size of * the loading indicator element. - * + * * @return */ protected boolean isCSSLoaded() { @@ -1144,12 +1146,12 @@ public class ApplicationConnection implements HasHandlers { /** * Shows the communication error notification. - * + * * @param details * Optional details for debugging. * @param statusCode * The status code returned for the request - * + * */ protected void showCommunicationError(String details, int statusCode) { VConsole.error("Communication error: " + details); @@ -1158,7 +1160,7 @@ public class ApplicationConnection implements HasHandlers { /** * Shows the authentication error notification. - * + * * @param details * Optional details for debugging. */ @@ -1169,7 +1171,7 @@ public class ApplicationConnection implements HasHandlers { /** * Shows the session expiration notification. - * + * * @param details * Optional details for debugging. */ @@ -1180,7 +1182,7 @@ public class ApplicationConnection implements HasHandlers { /** * Shows an error notification. - * + * * @param details * Optional details for debugging. * @param message @@ -1193,7 +1195,7 @@ public class ApplicationConnection implements HasHandlers { /** * Shows the error notification. - * + * * @param details * Optional details for debugging. */ @@ -1281,7 +1283,7 @@ public class ApplicationConnection implements HasHandlers { /** * This method is called after applying uidl change set to application. - * + * * It will clean current and queued variable change sets. And send next * change set if it exists. */ @@ -1300,7 +1302,7 @@ public class ApplicationConnection implements HasHandlers { /** * Cleans given queue of variable changes of such changes that came from * components that do not exist anymore. - * + * * @param variableBurst */ private void cleanVariableBurst( @@ -1325,7 +1327,7 @@ public class ApplicationConnection implements HasHandlers { * <p> * Used by the native "client.isActive" function. * </p> - * + * * @return true if deferred commands are (potentially) being executed, false * otherwise */ @@ -1340,7 +1342,7 @@ public class ApplicationConnection implements HasHandlers { /** * Returns the loading indicator used by this ApplicationConnection - * + * * @return The loading indicator for this ApplicationConnection */ public VLoadingIndicator getLoadingIndicator() { @@ -1349,7 +1351,7 @@ public class ApplicationConnection implements HasHandlers { /** * Determines whether or not the loading indicator is showing. - * + * * @return true if the loading indicator is visible * @deprecated As of 7.1. Use {@link #getLoadingIndicator()} and * {@link VLoadingIndicator#isVisible()}.isVisible() instead. @@ -1383,7 +1385,7 @@ public class ApplicationConnection implements HasHandlers { * server is received. * <p> * The initial id when no request has yet been processed is -1. - * + * * @return and id identifying the response */ public int getLastResponseId() { @@ -1806,13 +1808,13 @@ public class ApplicationConnection implements HasHandlers { /** * Sends the state change events created while updating the state * information. - * + * * This must be called after hierarchy change listeners have been * called. At least caption updates for the parent are strange if * fired from state change listeners and thus calls the parent * BEFORE the parent is aware of the child (through a * ConnectorHierarchyChangedEvent) - * + * * @param pendingStateChangeEvents * The events to send */ @@ -2127,7 +2129,7 @@ public class ApplicationConnection implements HasHandlers { * Updates the connector hierarchy and returns a list of events that * should be fired after update of the hierarchy and the state is * done. - * + * * @param json * The JSON containing the hierarchy information * @return A collection of events that should be fired when update @@ -2524,9 +2526,9 @@ public class ApplicationConnection implements HasHandlers { /** * Adds an explicit RPC method invocation to the send queue. - * + * * @since 7.0 - * + * * @param invocation * RPC method invocation * @param delayed @@ -2566,7 +2568,7 @@ public class ApplicationConnection implements HasHandlers { /** * Removes any pending invocation of the given method from the queue - * + * * @param invocation * The invocation to remove */ @@ -2584,12 +2586,12 @@ public class ApplicationConnection implements HasHandlers { /** * This method sends currently queued variable changes to server. It is * called when immediate variable update must happen. - * + * * To ensure correct order for variable changes (due servers multithreading * or network), we always wait for active request to be handler before * sending a new one. If there is an active request, we will put varible * "burst" to queue that will be purged after current request is handled. - * + * */ public void sendPendingVariableChanges() { if (!deferedSendPending) { @@ -2630,11 +2632,11 @@ public class ApplicationConnection implements HasHandlers { /** * Build the variable burst and send it to server. - * + * * When sync is forced, we also force sending of all pending variable-bursts * at the same time. This is ok as we can assume that DOM will never be * updated after this. - * + * * @param pendingInvocations * List of RPC method invocations to send */ @@ -2721,7 +2723,7 @@ public class ApplicationConnection implements HasHandlers { * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. * </p> - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2743,7 +2745,7 @@ public class ApplicationConnection implements HasHandlers { * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. * </p> - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2766,7 +2768,7 @@ public class ApplicationConnection implements HasHandlers { * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. * </p> - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2789,7 +2791,7 @@ public class ApplicationConnection implements HasHandlers { * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. * </p> - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2812,7 +2814,7 @@ public class ApplicationConnection implements HasHandlers { * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. * </p> - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2835,7 +2837,7 @@ public class ApplicationConnection implements HasHandlers { * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. * </p> - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2858,7 +2860,7 @@ public class ApplicationConnection implements HasHandlers { * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. * </p> - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2881,7 +2883,7 @@ public class ApplicationConnection implements HasHandlers { * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. * </p> - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2898,13 +2900,13 @@ public class ApplicationConnection implements HasHandlers { /** * Sends a new value for the given paintables given variable to the server. - * + * * The update is actually queued to be sent at a suitable time. If immediate * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. - * + * * A null array is sent as an empty array. - * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2921,14 +2923,14 @@ public class ApplicationConnection implements HasHandlers { /** * Sends a new value for the given paintables given variable to the server. - * + * * The update is actually queued to be sent at a suitable time. If immediate * is true, the update is sent as soon as possible. If immediate is false, * the update will be sent along with the next immediate update. </p> - * + * * A null array is sent as an empty array. - * - * + * + * * @param paintableId * the id of the paintable that owns the variable * @param variableName @@ -2945,7 +2947,7 @@ public class ApplicationConnection implements HasHandlers { /** * Does absolutely nothing. Replaced by {@link LayoutManager}. - * + * * @param container * @deprecated As of 7.0, serves no purpose */ @@ -2967,7 +2969,7 @@ public class ApplicationConnection implements HasHandlers { /** * Returns false - * + * * @param paintable * @return false, always * @deprecated As of 7.0, serves no purpose @@ -2979,7 +2981,7 @@ public class ApplicationConnection implements HasHandlers { /** * Returns false - * + * * @param paintable * @return false, always * @deprecated As of 7.0, serves no purpose @@ -3000,16 +3002,16 @@ public class ApplicationConnection implements HasHandlers { /** * Get either an existing ComponentConnector or create a new * ComponentConnector with the given type and id. - * + * * If a ComponentConnector with the given id already exists, returns it. * Otherwise creates and registers a new ComponentConnector of the given * type. - * + * * @param connectorId * Id of the paintable * @param connectorType * Type of the connector, as passed from the server side - * + * * @return Either an existing ComponentConnector or a new ComponentConnector * of the given type */ @@ -3022,15 +3024,15 @@ public class ApplicationConnection implements HasHandlers { /** * Creates a new ServerConnector with the given type and id. - * + * * Creates and registers a new ServerConnector of the given type. Should * never be called with the connector id of an existing connector. - * + * * @param connectorId * Id of the new connector * @param connectorType * Type of the connector, as passed from the server side - * + * * @return A new ServerConnector of the given type */ private ServerConnector createAndRegisterConnector(String connectorId, @@ -3050,7 +3052,7 @@ public class ApplicationConnection implements HasHandlers { /** * Gets a recource that has been pre-loaded via UIDL, such as custom * layouts. - * + * * @param name * identifier of the resource to get * @return the resource @@ -3061,7 +3063,7 @@ public class ApplicationConnection implements HasHandlers { /** * Singleton method to get instance of app's context menu. - * + * * @return VContextMenu object */ public VContextMenu getContextMenu() { @@ -3076,7 +3078,7 @@ public class ApplicationConnection implements HasHandlers { /** * Gets an {@link Icon} instance corresponding to a URI. - * + * * @since 7.2 * @param uri * @return Icon object @@ -3098,7 +3100,7 @@ public class ApplicationConnection implements HasHandlers { * Translates custom protocols in UIDL URI's to be recognizable by browser. * All uri's from UIDL should be routed via this method before giving them * to browser due URI's in UIDL may contain custom protocols like theme://. - * + * * @param uidlUri * Vaadin URI from uidl * @return translated URI ready for browser @@ -3170,7 +3172,7 @@ public class ApplicationConnection implements HasHandlers { /** * Gets the URI for the current theme. Can be used to reference theme * resources. - * + * * @return URI to the current theme */ public String getThemeUri() { @@ -3180,7 +3182,7 @@ public class ApplicationConnection implements HasHandlers { /** * Listens for Notification hide event, and redirects. Used for system * messages, such as session expired. - * + * */ private class NotificationRedirect implements VNotification.EventListener { String url; @@ -3209,7 +3211,7 @@ public class ApplicationConnection implements HasHandlers { /** * Gets the token (aka double submit cookie) that the server uses to protect * against Cross Site Request Forgery attacks. - * + * * @return the CSRF token string */ public String getCsrfToken() { @@ -3219,7 +3221,7 @@ public class ApplicationConnection implements HasHandlers { /** * Use to notify that the given component's caption has changed; layouts may * have to be recalculated. - * + * * @param component * the Paintable whose caption has changed * @deprecated As of 7.0.2, has not had any effect for a long time @@ -3231,7 +3233,7 @@ public class ApplicationConnection implements HasHandlers { /** * Gets the main view - * + * * @return the main view */ public UIConnector getUIConnector() { @@ -3240,7 +3242,7 @@ public class ApplicationConnection implements HasHandlers { /** * Gets the {@link ApplicationConfiguration} for the current application. - * + * * @see ApplicationConfiguration * @return the configuration for this application */ @@ -3253,7 +3255,7 @@ public class ApplicationConnection implements HasHandlers { * list of events which has server side listeners is updated automatically * before the component is updated so the value is correct if called from * updatedFromUIDL. - * + * * @param paintable * The connector to register event listeners for * @param eventIdentifier @@ -3273,7 +3275,7 @@ public class ApplicationConnection implements HasHandlers { /** * Adds the get parameters to the uri and returns the new uri that contains * the parameters. - * + * * @param uri * The uri to which the parameters should be added. * @param extraParams @@ -3326,7 +3328,7 @@ public class ApplicationConnection implements HasHandlers { /** * Get VTooltip instance related to application connection - * + * * @return VTooltip instance */ public VTooltip getVTooltip() { @@ -3338,7 +3340,7 @@ public class ApplicationConnection implements HasHandlers { * this method is now handled by the state change event handler in * AbstractComponentConnector. The only function this method has is to * return true if the UIDL is a "cached" update. - * + * * @param component * @param uidl * @param manageCaption @@ -3389,7 +3391,7 @@ public class ApplicationConnection implements HasHandlers { * Schedules a heartbeat request to occur after the configured heartbeat * interval elapses if the interval is a positive number. Otherwise, does * nothing. - * + * * @deprecated as of 7.2, use {@link Heartbeat#schedule()} instead */ @Deprecated @@ -3403,7 +3405,7 @@ public class ApplicationConnection implements HasHandlers { * Heartbeat requests are used to inform the server that the client-side is * still alive. If the client page is closed or the connection lost, the * server will eventually close the inactive UI. - * + * * @deprecated as of 7.2, use {@link Heartbeat#send()} instead */ @Deprecated @@ -3427,7 +3429,7 @@ public class ApplicationConnection implements HasHandlers { /** * This method can be used to postpone rendering of a response for a short * period of time (e.g. to avoid the rendering process during animation). - * + * * @param lock */ public void suspendReponseHandling(Object lock) { @@ -3436,7 +3438,7 @@ public class ApplicationConnection implements HasHandlers { /** * Resumes the rendering process once all locks have been removed. - * + * * @param lock */ public void resumeResponseHandling(Object lock) { @@ -3481,7 +3483,7 @@ public class ApplicationConnection implements HasHandlers { /** * Sets the delegate that is called whenever a communication error occurrs. - * + * * @param delegate * the delegate. */ @@ -3524,7 +3526,7 @@ public class ApplicationConnection implements HasHandlers { /** * Gets the active connector for focused element in browser. - * + * * @return Connector for focused element or null. */ private ComponentConnector getActiveConnector() { @@ -3538,7 +3540,7 @@ public class ApplicationConnection implements HasHandlers { /** * Sets the status for the push connection. - * + * * @param enabled * <code>true</code> to enable the push connection; * <code>false</code> to disable the push connection. @@ -3588,7 +3590,7 @@ public class ApplicationConnection implements HasHandlers { /** * Returns a human readable string representation of the method used to * communicate with the server. - * + * * @since 7.1 * @return A string representation of the current transport type */ diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index 48e17cde05..5073e0ce5d 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -37,7 +37,7 @@ import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; /** * The default {@link PushConnection} implementation that uses Atmosphere for * handling the communication channel. - * + * * @author Vaadin Ltd * @since 7.1 */ @@ -171,8 +171,12 @@ public class AtmospherePushConnection implements PushConnection { + ApplicationConstants.PUSH_PATH + '/'); String extraParams = UIConstants.UI_ID_PARAMETER + "=" + connection.getConfiguration().getUIId(); - extraParams += "&" + ApplicationConstants.CSRF_TOKEN_PARAMETER + "=" - + connection.getCsrfToken(); + + if (!connection.getCsrfToken().equals( + ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE)) { + extraParams += "&" + ApplicationConstants.CSRF_TOKEN_PARAMETER + + "=" + connection.getCsrfToken(); + } // uri is needed to identify the right connection when closing uri = ApplicationConnection.addGetParameters(baseUrl, extraParams); @@ -239,9 +243,9 @@ public class AtmospherePushConnection implements PushConnection { /** * Called whenever a server push connection is established (or * re-established). - * + * * @param response - * + * * @since 7.2 */ protected void onConnect(AtmosphereResponse response) { @@ -330,7 +334,7 @@ public class AtmospherePushConnection implements PushConnection { /** * Called if the push connection fails. Atmosphere will automatically retry * the connection until successful. - * + * */ protected void onError(AtmosphereResponse response) { state = State.DISCONNECTED; @@ -448,7 +452,7 @@ public class AtmospherePushConnection implements PushConnection { contentType: 'application/json; charset=UTF-8', reconnectInterval: 5000, timeout: -1, - maxReconnectOnClose: 10000000, + maxReconnectOnClose: 10000000, trackMessageLength: true, enableProtocol: true, messageDelimiter: String.fromCharCode(@com.vaadin.shared.communication.PushConstants::MESSAGE_DELIMITER) @@ -501,7 +505,7 @@ public class AtmospherePushConnection implements PushConnection { private static native boolean isAtmosphereLoaded() /*-{ - return $wnd.jQueryVaadin != undefined; + return $wnd.jQueryVaadin != undefined; }-*/; private void runWhenAtmosphereLoaded(final Command command) { diff --git a/server/src/com/vaadin/server/communication/ServerRpcHandler.java b/server/src/com/vaadin/server/communication/ServerRpcHandler.java index 6f1d44d087..9107a4e049 100644 --- a/server/src/com/vaadin/server/communication/ServerRpcHandler.java +++ b/server/src/com/vaadin/server/communication/ServerRpcHandler.java @@ -78,7 +78,13 @@ public class ServerRpcHandler implements Serializable { public RpcRequest(String jsonString, VaadinRequest request) throws JSONException { json = new JSONObject(jsonString); - csrfToken = json.getString(ApplicationConstants.CSRF_TOKEN); + + String csrfToken = json.optString(ApplicationConstants.CSRF_TOKEN); + if (csrfToken.equals("")) { + csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE; + } + this.csrfToken = csrfToken; + if (request.getService().getDeploymentConfiguration() .isSyncIdCheckEnabled()) { syncId = json.getInt(ApplicationConstants.SERVER_SYNC_ID); diff --git a/server/tests/src/com/vaadin/tests/server/CsrfTokenMissingTestServer.java b/server/tests/src/com/vaadin/tests/server/CsrfTokenMissingTestServer.java new file mode 100644 index 0000000000..30f1c85fef --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/CsrfTokenMissingTestServer.java @@ -0,0 +1,248 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.server; + +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.servlet.http.HttpServletRequest; + +import org.easymock.EasyMock; +import org.json.JSONException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.server.ServiceException; +import com.vaadin.server.VaadinService; +import com.vaadin.server.VaadinServlet; +import com.vaadin.server.VaadinServletRequest; +import com.vaadin.server.VaadinServletService; +import com.vaadin.server.VaadinSession; +import com.vaadin.server.communication.ServerRpcHandler.RpcRequest; +import com.vaadin.shared.ApplicationConstants; +import com.vaadin.tests.util.AlwaysLockedVaadinSession; +import com.vaadin.tests.util.MockDeploymentConfiguration; + +/** + * Test the actual csrf token validation by the server. + * + * @since + * @author Vaadin Ltd + */ +public class CsrfTokenMissingTestServer { + + // Dummy fields just to run the test. + private VaadinServlet mockServlet; + + // The mock deployment configuration. + private MockDeploymentConfiguration mockDeploymentConfiguration; + + private VaadinServletService mockService; + + // The mock UI session. + private VaadinSession mockSession; + + // The mock vaadin request. + private VaadinServletRequest vaadinRequest; + + /** + * Initialize the mock servlet and other stuff for our tests. + */ + @Before + public void initMockStuff() throws ServiceException { + mockServlet = new VaadinServlet(); + mockDeploymentConfiguration = new MockDeploymentConfiguration(); + + mockService = new VaadinServletService(mockServlet, + mockDeploymentConfiguration); + + mockSession = new AlwaysLockedVaadinSession(mockService); + + vaadinRequest = new VaadinServletRequest( + EasyMock.createMock(HttpServletRequest.class), mockService); + + } + + private enum TokenType { + MISSING, INVALID, VALID + } + + private TokenType tokenType; + + private String invalidToken; + + public String getInvalidToken() { + if (invalidToken == null) { + // Just making sure this will never be in the same format as a valid + // token. + invalidToken = UUID.randomUUID().toString().substring(1); + } + return invalidToken; + } + + private String getValidToken() { + return mockSession.getCsrfToken(); + } + + /* + * Gets the payload with the default token. + */ + private String getPayload() { + switch (tokenType) { + case MISSING: + return getPayload(null); + + case INVALID: + return getPayload(getInvalidToken()); + + case VALID: + return getPayload(getValidToken()); + } + + return null; + } + + /* + * Gets the payload with the specified token. + */ + private String getPayload(String token) { + return "{" + + (token != null ? "\"csrfToken\":" + "\"" + token + "\", " + : "") + + "\"rpc\":[[\"0\",\"com.vaadin.shared.ui.ui.UIServerRpc\",\"resize\",[\"449\",\"1155\",\"1155\",\"449\"]],[\"4\",\"com.vaadin.shared.ui.button.ButtonServerRpc\",\"click\",[{\"clientY\":\"53\", \"clientX\":\"79\", \"shiftKey\":false, \"button\":\"LEFT\", \"ctrlKey\":false, \"type\":\"1\", \"metaKey\":false, \"altKey\":false, \"relativeY\":\"17\", \"relativeX\":\"61\"}]]], \"syncId\":1}"; + } + + /* + * Init the test parameters. + */ + private void initTest(boolean enableSecurity, TokenType tokenType) { + mockDeploymentConfiguration.setXsrfProtectionEnabled(enableSecurity); + this.tokenType = tokenType; + } + + /* + * Create the requets. + */ + private RpcRequest createRequest() { + try { + return new RpcRequest(getPayload(), vaadinRequest); + } catch (JSONException e) { + LOGGER.log(Level.SEVERE, "", e); + + Assert.assertTrue(false); + return null; + } + } + + /* + * Gets whether the token from the request is the default one. + */ + private boolean isDefaultToken(RpcRequest rpcRequest) { + return ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE.equals(rpcRequest + .getCsrfToken()); + } + + /* + * Gets whether the token from the request is the invalid one. + */ + private boolean isInvalidToken(RpcRequest rpcRequest) { + return getInvalidToken().equals(rpcRequest.getCsrfToken()); + } + + /* + * Gets whether the token from the request is the valid one. + */ + private boolean isValidToken(RpcRequest rpcRequest) { + return getValidToken().equals(rpcRequest.getCsrfToken()); + } + + /* + * Gets whether the token from the request is valid. + */ + private boolean isRequestValid(RpcRequest rpcRequest) { + return VaadinService.isCsrfTokenValid(mockSession, + rpcRequest.getCsrfToken()); + } + + private static Logger LOGGER = Logger + .getLogger(CsrfTokenMissingTestServer.class.getName()); + static { + LOGGER.setLevel(Level.ALL); + } + + @Test + public void securityOnAndNoToken() { + initTest(true, TokenType.MISSING); + + RpcRequest rpcRequest = createRequest(); + + Assert.assertTrue(isDefaultToken(rpcRequest)); + Assert.assertFalse(isRequestValid(rpcRequest)); + } + + @Test + public void securityOffAndNoToken() { + initTest(false, TokenType.MISSING); + + RpcRequest rpcRequest = createRequest(); + + Assert.assertTrue(isDefaultToken(rpcRequest)); + Assert.assertTrue(isRequestValid(rpcRequest)); + } + + @Test + public void securityOnAndInvalidToken() { + initTest(true, TokenType.INVALID); + + RpcRequest rpcRequest = createRequest(); + + Assert.assertTrue(isInvalidToken(rpcRequest)); + Assert.assertFalse(isRequestValid(rpcRequest)); + } + + @Test + public void securityOffAndInvalidToken() { + initTest(false, TokenType.INVALID); + + RpcRequest rpcRequest = createRequest(); + + Assert.assertTrue(isInvalidToken(rpcRequest)); + Assert.assertTrue(isRequestValid(rpcRequest)); + } + + @Test + public void securityOnAndValidToken() { + initTest(true, TokenType.VALID); + + RpcRequest rpcRequest = createRequest(); + + Assert.assertTrue(isValidToken(rpcRequest)); + Assert.assertTrue(isRequestValid(rpcRequest)); + } + + @Test + public void securityOffAndValidToken() { + initTest(false, TokenType.VALID); + + RpcRequest rpcRequest = createRequest(); + + Assert.assertTrue(isValidToken(rpcRequest)); + Assert.assertTrue(isRequestValid(rpcRequest)); + } + +} diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java index da4ac7450d..15eefe3b21 100644 --- a/shared/src/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/com/vaadin/shared/ApplicationConstants.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -86,7 +86,7 @@ public class ApplicationConstants implements Serializable { /** * The name of the debug version of the javascript containing push support. * The file is located in the VAADIN directory. - * + * * @since 7.1.6 */ public static final String VAADIN_PUSH_DEBUG_JS = "vaadinPush.debug.js"; @@ -98,14 +98,14 @@ public class ApplicationConstants implements Serializable { /** * The name of the parameter used to transmit RPC invocations - * + * * @since 7.2 */ public static final String RPC_INVOCATIONS = "rpc"; /** * The name of the parameter used to transmit the CSRF token - * + * * @since 7.2 */ public static final String CSRF_TOKEN = "csrfToken"; @@ -114,9 +114,15 @@ public class ApplicationConstants implements Serializable { * The name of the parameter used to transmit the sync id. The value can be * set to -1 e.g. when testing with pre-recorded requests to make the * framework ignore the sync id. - * + * * @see com.vaadin.ui.ConnectorTracker#getCurrentSyncId() * @since 7.2 */ public static final String SERVER_SYNC_ID = "syncId"; + + /** + * Default value to use in case the security protection is disabled. + */ + public static final String CSRF_TOKEN_DEFAULT_VALUE = "init"; + } diff --git a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml index fd52e5cd0e..2c25c54e04 100644 --- a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml +++ b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml @@ -13,4 +13,9 @@ <when-type-is class="com.vaadin.client.communication.PushConnection" /> </replace-with> + <replace-with + class="com.vaadin.tests.widgetset.client.MockApplicationConnection"> + <when-type-is class="com.vaadin.client.ApplicationConnection" /> + </replace-with> + </module> diff --git a/uitest/src/com/vaadin/tests/widgetset/client/MockApplicationConnection.java b/uitest/src/com/vaadin/tests/widgetset/client/MockApplicationConnection.java new file mode 100644 index 0000000000..4ee5b71387 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/MockApplicationConnection.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.client; + +import java.util.Date; +import java.util.logging.Logger; + +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONValue; +import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ValueMap; +import com.vaadin.shared.ApplicationConstants; +import com.vaadin.tests.widgetset.server.csrf.ui.CsrfTokenDisabled; + +/** + * Mock ApplicationConnection for several issues where we need to hack it. + * + * @since + * @author Vaadin Ltd + */ +public class MockApplicationConnection extends ApplicationConnection { + + private static final Logger LOGGER = Logger + .getLogger(MockApplicationConnection.class.getName()); + + // The last token received from the server. + private String lastCsrfTokenReceiver; + + // The last token sent to the server. + private String lastCsrfTokenSent; + + /** + * Provide the last token received from the server. <br/> + * We added this to test the change done on CSRF token. + * + * @see CsrfTokenDisabled + */ + public String getLastCsrfTokenReceiver() { + return lastCsrfTokenReceiver; + } + + /** + * Provide the last token sent to the server. <br/> + * We added this to test the change done on CSRF token. + * + * @see CsrfTokenDisabled + */ + public String getLastCsrfTokenSent() { + return lastCsrfTokenSent; + } + + @Override + protected void handleUIDLMessage(Date start, String jsonText, ValueMap json) { + lastCsrfTokenReceiver = json + .getString(ApplicationConstants.UIDL_SECURITY_TOKEN_ID); + + super.handleUIDLMessage(start, jsonText, json); + } + + @Override + protected void doUidlRequest(String uri, JSONObject payload) { + JSONValue jsonValue = payload.get(ApplicationConstants.CSRF_TOKEN); + lastCsrfTokenSent = jsonValue != null ? jsonValue.toString() : null; + + super.doUidlRequest(uri, payload); + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/csrf/CsrfButtonConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/csrf/CsrfButtonConnector.java new file mode 100644 index 0000000000..cf24ed6921 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/csrf/CsrfButtonConnector.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.client.csrf; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.gwt.core.shared.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.client.ui.VButton; +import com.vaadin.shared.ui.Connect; +import com.vaadin.tests.widgetset.client.MockApplicationConnection; +import com.vaadin.tests.widgetset.server.csrf.CsrfButton; + +/** + * Dummy connector to test our CSRF bug. See #14111. + * + * @author Vaadin Ltd + */ +@SuppressWarnings("serial") +@Connect(CsrfButton.class) +public class CsrfButtonConnector extends AbstractComponentConnector { + + static Logger logger = Logger + .getLogger(CsrfButtonConnector.class.getName()); + static { + logger.setLevel(Level.ALL); + } + + @Override + public VButton getWidget() { + return (VButton) super.getWidget(); + } + + @Override + protected VButton createWidget() { + return GWT.create(VButton.class); + } + + public final static String ID = "CsrfButton"; + + @Override + public void init() { + super.init(); + + getWidget().getElement().setId(ID); + getWidget().setText(csrfTokenInfo()); + getWidget().addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + getWidget().setText(csrfTokenInfo()); + } + }); + } + + private String csrfTokenInfo() { + return getMockConnection().getCsrfToken() + ", " + + getMockConnection().getLastCsrfTokenReceiver() + ", " + + getMockConnection().getLastCsrfTokenSent(); + } + + private MockApplicationConnection getMockConnection() { + return (MockApplicationConnection) getConnection(); + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/csrf/CsrfButton.java b/uitest/src/com/vaadin/tests/widgetset/server/csrf/CsrfButton.java new file mode 100644 index 0000000000..567127927d --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/csrf/CsrfButton.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.server.csrf; + +import com.vaadin.ui.AbstractComponent; + +/** + * Dummy client connector to link with the client functionality if the + * CsrfToken. + * + * @since + * @author Vaadin Ltd + */ +@SuppressWarnings("serial") +public class CsrfButton extends AbstractComponent { + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/AbstractCsrfTokenUI.java b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/AbstractCsrfTokenUI.java new file mode 100644 index 0000000000..f8f1754385 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/AbstractCsrfTokenUI.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.server.csrf.ui; + +import com.vaadin.annotations.Widgetset; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.widgetset.TestingWidgetSet; +import com.vaadin.tests.widgetset.server.csrf.CsrfButton; +import com.vaadin.ui.Button; +import com.vaadin.ui.Label; + +/** + * Abstract UI to test the CSRF token issue as reported in (#14111) + * + * @since + * @author Vaadin Ltd + */ +@SuppressWarnings("serial") +@Widgetset(TestingWidgetSet.NAME) +public abstract class AbstractCsrfTokenUI extends AbstractTestUI { + + public static final String PRESS_ID = "PressMe"; + + @Override + protected void setup(VaadinRequest request) { + + addComponent(new Label("The button's text is the client token:")); + addComponent(new CsrfButton()); + addComponent(new Label("This one is from the server")); + addComponent(new Label(getSession().getCsrfToken())); + Button pressMe = new Button("Click me to send a request"); + pressMe.setId(PRESS_ID); + addComponent(pressMe); + } + + @Override + protected String getTestDescription() { + return "Remove csrfToken from the request if security protection is disabled."; + } + + @Override + protected Integer getTicketNumber() { + return 14111; + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/AbstractCsrfTokenUITest.java b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/AbstractCsrfTokenUITest.java new file mode 100644 index 0000000000..614eaa063e --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/AbstractCsrfTokenUITest.java @@ -0,0 +1,116 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.server.csrf.ui; + +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.tests.widgetset.client.csrf.CsrfButtonConnector; + +public abstract class AbstractCsrfTokenUITest extends MultiBrowserTest { + + static final Logger LOGGER = Logger.getLogger(AbstractCsrfTokenUITest.class + .getName()); + + @Test + public void testTokens() { + openTestURL(); + + final By debugButton = By.id(CsrfButtonConnector.ID); + + final String debugMessage1 = getDriver().findElement(debugButton) + .getText(); + + getDriver().findElement(By.id(CsrfTokenDisabled.PRESS_ID)).click(); + + waitUntil(new ExpectedCondition<Boolean>() { + + @Override + public Boolean apply(WebDriver input) { + getDriver().findElement(debugButton).click(); + String debugMessage2 = input.findElement(debugButton).getText(); + + LOGGER.log(Level.INFO, "1: " + debugMessage1); + LOGGER.log(Level.INFO, "2: " + debugMessage2); + + if (!debugMessage1.equals(debugMessage2)) { + + compareMessage(split(debugMessage1), split(debugMessage2)); + + LOGGER.log(Level.INFO, "DONE"); + + return true; + + } else { + return false; + } + } + }); + } + + private TokenGroup split(String debugMessage) { + StringTokenizer tokenizer = new StringTokenizer(debugMessage, ", \""); + + return new TokenGroup(tokenizer.nextToken(), tokenizer.nextToken(), + tokenizer.nextToken()); + } + + /* + * Just implement this. + */ + protected abstract boolean compareMessage(TokenGroup tokenGroup1, + TokenGroup tokenGroup2); + + boolean isNullOrUndefined(String value) { + return isNull(value) || isUndefined(value); + } + + boolean isUndefined(String value) { + return value.equals("undefined"); + } + + boolean isNull(String value) { + return value.equals("null"); + } + + /* + * Wrapps all tokens from the client app. + */ + static class TokenGroup { + + public final String clientToken; + + public final String tokenReceivedFromServer; + + public final String tokenSentToServer; + + public TokenGroup(String clientToken, String tokenReceivedFromServer, + String tokenSentToServer) { + this.clientToken = clientToken; + this.tokenReceivedFromServer = tokenReceivedFromServer; + this.tokenSentToServer = tokenSentToServer; + } + + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenDisabled.java b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenDisabled.java new file mode 100644 index 0000000000..6283285b40 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenDisabled.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.server.csrf.ui; + +import com.vaadin.launcher.CustomDeploymentConfiguration; +import com.vaadin.launcher.CustomDeploymentConfiguration.Conf; + +/** + * When the disable-xsrf-protection is true csrfToken is not present anymore + * with the requests.<br/> + * This is useful mostly when the client is not Vaadin and so it will not push + * the parameter anyway. So now the server knows how to deal the issue if the + * csrfToken is not present. + * + * @since + * @author Vaadin Ltd + */ +@SuppressWarnings("serial") +@CustomDeploymentConfiguration({ @Conf(name = "disable-xsrf-protection", value = "true") }) +public class CsrfTokenDisabled extends AbstractCsrfTokenUI { + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenDisabledTest.java b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenDisabledTest.java new file mode 100644 index 0000000000..504425fead --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenDisabledTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.server.csrf.ui; + +import com.vaadin.shared.ApplicationConstants; + +/** + * Test the CSRF Token issue. + * + * @since + * @author Vaadin Ltd + */ +public class CsrfTokenDisabledTest extends AbstractCsrfTokenUITest { + + @Override + protected boolean compareMessage(TokenGroup tokenGroup1, + TokenGroup tokenGroup2) { + + return tokenGroup1.clientToken + .equals(ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE) + && isUndefined(tokenGroup1.tokenReceivedFromServer) + && isUndefined(tokenGroup1.tokenSentToServer) + && tokenGroup2.clientToken + .equals(ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE) + && isUndefined(tokenGroup2.tokenReceivedFromServer) + // This is it actually, no token sent to the server. + && isNull(tokenGroup2.tokenSentToServer); + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenEnabled.java b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenEnabled.java new file mode 100644 index 0000000000..cd02c6da77 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenEnabled.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.server.csrf.ui; + +import com.vaadin.launcher.CustomDeploymentConfiguration; +import com.vaadin.launcher.CustomDeploymentConfiguration.Conf; + +@SuppressWarnings("serial") +@CustomDeploymentConfiguration({ @Conf(name = "disable-xsrf-protection", value = "false") }) +public class CsrfTokenEnabled extends AbstractCsrfTokenUI { + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenEnabledTest.java b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenEnabledTest.java new file mode 100644 index 0000000000..1d51f1c372 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/server/csrf/ui/CsrfTokenEnabledTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.server.csrf.ui; + +/** + * Test the CSRF Token issue. + * + * @since + * @author Vaadin Ltd + */ +public class CsrfTokenEnabledTest extends AbstractCsrfTokenUITest { + + @Override + protected boolean compareMessage(TokenGroup tokenGroup1, + TokenGroup tokenGroup2) { + + return tokenGroup1.clientToken.equals(tokenGroup2.clientToken) + // Valid token received and set on the client + && tokenGroup1.clientToken + .equals(tokenGroup1.tokenReceivedFromServer) + // No token sent yet to the server. + && isUndefined(tokenGroup1.tokenSentToServer) + // Token is sent to the server. + && tokenGroup2.clientToken + .equals(tokenGroup2.tokenSentToServer) + // And no more token received from the server. + && isUndefined(tokenGroup2.tokenReceivedFromServer); + } + +} |