/*
* Copyright 2000-2016 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.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.vaadin.server.MockServletConfig;
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;
import elemental.json.JsonException;
/**
* Test the actual csrf token validation by the server.
*
* @since
* @author Vaadin Ltd
*/
public class CsrfTokenMissingTest {
// 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, ServletException {
mockServlet = new VaadinServlet();
mockServlet.init(new MockServletConfig());
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 final Logger LOGGER = Logger
.getLogger(CsrfTokenMissingTest.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));
}
}