/* * Copyright 2011 Google Inc. * * 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.google.gwt.user.client.rpc; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.Cookies; /** * Tests XSRF protection provided by {@link XsrfProtectedServiceServlet} and * {@link XsrfTokenService}. */ public class XsrfProtectionTest extends RpcTestBase { public static final String SESSION_COOKIE_NAME = "MYSESSIONCOOKIE"; @Override protected void gwtSetUp() { // MD5 test vector Cookies.setCookie(SESSION_COOKIE_NAME, "abc"); } @Override protected void gwtTearDown() { Cookies.removeCookie(SESSION_COOKIE_NAME); } protected static XsrfTestServiceAsync getAsyncService() { XsrfTestServiceAsync service = (XsrfTestServiceAsync) GWT.create(XsrfTestService.class); ((ServiceDefTarget) service).setServiceEntryPoint(GWT.getModuleBaseURL() + "xsrftestservice"); return service; } protected static XsrfTokenServiceAsync getAsyncXsrfService() { XsrfTokenServiceAsync service = (XsrfTokenServiceAsync) GWT.create(XsrfTokenService.class); ((ServiceDefTarget) service).setServiceEntryPoint(GWT.getModuleBaseURL() + "xsrfmock"); return service; } public void testRpcWithoutXsrfTokenFails() throws Exception { XsrfTestServiceAsync service = getAsyncService(); delayTestFinishForRpc(); service.drink("kumys", new AsyncCallback<Void>() { public void onFailure(Throwable caught) { RpcTokenException e = (RpcTokenException) caught; assertTrue(e.getMessage().contains("XSRF token missing")); checkServerState("kumys", false); } public void onSuccess(Void result) { fail("Should've failed without XSRF token"); } }); } public void testRpcWithBadXsrfTokenFails() throws Exception { XsrfToken badToken = new XsrfToken("Invalid Token"); XsrfTestServiceAsync service = getAsyncService(); ((HasRpcToken) service).setRpcToken(badToken); delayTestFinishForRpc(); service.drink("maksym", new AsyncCallback<Void>() { public void onSuccess(Void result) { fail("Should've failed with bad XSRF token"); } public void onFailure(Throwable caught) { checkServerState("maksym", false); } }); } public void testXsrfTokenService() throws Exception { XsrfTokenServiceAsync xsrfService = getAsyncXsrfService(); delayTestFinishForRpc(); xsrfService.getNewXsrfToken(new AsyncCallback<XsrfToken>() { public void onSuccess(XsrfToken result) { assertNotNull(result); assertNotNull(result.getToken()); // MD5("abc") assertEquals("900150983CD24FB0D6963F7D28E17F72", result.getToken()); finishTest(); } public void onFailure(Throwable caught) { TestSetValidator.rethrowException(caught); } }); } public void testRpcWithXsrfToken() throws Exception { XsrfTokenServiceAsync xsrfService = getAsyncXsrfService(); delayTestFinishForRpc(); xsrfService.getNewXsrfToken(new AsyncCallback<XsrfToken>() { public void onFailure(Throwable caught) { TestSetValidator.rethrowException(caught); } public void onSuccess(XsrfToken result) { XsrfTestServiceAsync service = getAsyncService(); ((HasRpcToken) service).setRpcToken(result); service.drink("airan", new AsyncCallback<Void>() { public void onFailure(Throwable caught) { TestSetValidator.rethrowException(caught); } public void onSuccess(Void result) { checkServerState("airan", true); } }); } }); } public void testXsrfTokenWithDifferentSessionCookieFails() throws Exception { XsrfTokenServiceAsync xsrfService = getAsyncXsrfService(); final XsrfTestServiceAsync service = getAsyncService(); delayTestFinishForRpc(); xsrfService.getNewXsrfToken(new AsyncCallback<XsrfToken>() { public void onFailure(Throwable caught) { TestSetValidator.rethrowException(caught); } public void onSuccess(XsrfToken result) { // Ensure it's MD5 assertEquals(32, result.getToken().length()); ((HasRpcToken) service).setRpcToken(result); // change cookie to ensure verification fails since // XSRF token was derived from previous cookie value Cookies.setCookie(SESSION_COOKIE_NAME, "sometingrandom"); service.drink("bozo", new AsyncCallback<Void>() { public void onFailure(Throwable caught) { RpcTokenException e = (RpcTokenException) caught; assertTrue(e.getMessage().contains( "Invalid XSRF token")); checkServerState("bozo", false); } public void onSuccess(Void result) { fail("Should've failed since session cookie has changed"); } }); } }); } private void checkServerState(String drink, final boolean stateShouldChange) { XsrfTestServiceAsync service = getAsyncService(); service.checkIfDrankDrink(drink, new AsyncCallback<Boolean>() { public void onSuccess(Boolean result) { assertTrue(stateShouldChange == result); finishTest(); } public void onFailure(Throwable caught) { TestSetValidator.rethrowException(caught); } }); } }