/******************************************************************************* * Copyright (c) 2010 Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cambridge Semantics Incorporated *******************************************************************************/ package org.openanzo.test; import java.util.Properties; import org.apache.commons.httpclient.Cookie; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.openanzo.rdf.utils.Pair; import org.openanzo.services.EncryptedTokenAuthenticatorConstants; import org.openanzo.services.ServicesProperties; import org.openanzo.servlet.control.ControlServlet; /** * Tests for the EncryptedTokenAuthorization class which test whether the class properly protects servlets. * * This class was built to test the situation found in ticket http://www.openanzo.org/projects/openanzo/ticket/852 in which a request to authenticate was * handled by both the authenticator and the servlet when it should have only been handled by the authenticator. * * Many of these tests depend on the 'ControlServlet' being setup and responding to commands to increment and read a counter that the servlet keeps internally. * * @author Jordi Albornoz Mulligan ( <a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com </a>) */ public class TestEncryptedTokenAuthorizationBlocksServletAccess extends AbstractTest { private static final String PROTECTED_URI_PATH = "protected/"; private String getControlServletURI() { String port = getProperties().getProperty("http.port"); String uri = "http://localhost:" + port + "/control/"; return uri; } private Pair<String, String> getDefaultUserAndPassword() throws Exception { Properties properties = getProperties(); String user = ServicesProperties.getUser(properties, "default"); String password = ServicesProperties.getPassword(properties, "123"); Pair<String, String> info = new Pair<String, String>(user, password); return info; } private void resetServletCounter() throws Exception { HttpClient client = new HttpClient(); String uri = getControlServletURI() + ControlServlet.OPERATION_URI_SUFFIX_COUNTER_RESET; GetMethod request = new GetMethod(uri); request.addRequestHeader("X-Requested-With", "XMLHttpRequest"); client.executeMethod(request); int statusCode = request.getStatusCode(); assertEquals("Invalid status code. Status text: " + request.getStatusText(), HttpStatus.SC_OK, statusCode); assertEquals("0", request.getResponseBodyAsString()); } /** * Make sure that the ControlServlet's incrementing counter functionality works properly since most of the other tests depend on it. * * @throws Exception */ public void testControlServletIncrementsCounter() throws Exception { resetServletCounter(); // Try to tell the servlet to increment the counter (via an unprotected path) HttpClient client = new HttpClient(); GetMethod request = new GetMethod(getControlServletURI() + "increment_the_counter"); request.addRequestHeader("X-Requested-With", "XMLHttpRequest"); client.executeMethod(request); int statusCode = request.getStatusCode(); assertEquals("Invalid status code. Status text: " + request.getStatusText(), HttpStatus.SC_OK, statusCode); assertEquals("1", request.getResponseBodyAsString()); // Increment again client = new HttpClient(); request = new GetMethod(getControlServletURI() + "increment_it_again"); request.addRequestHeader("X-Requested-With", "XMLHttpRequest"); client.executeMethod(request); statusCode = request.getStatusCode(); assertEquals("Invalid status code. Status text: " + request.getStatusText(), HttpStatus.SC_OK, statusCode); assertEquals("2", request.getResponseBodyAsString()); } /** * Trying to access a protected path without proper authentication should prevent access to the servlet. * * @throws Exception */ public void testUnauthenticatedProtectedPathAccessDoesNotReachServlet() throws Exception { resetServletCounter(); // Try to tell the servlet to increment the counter via a path that is protected by authentication. // This should fail via an authentication error. HttpClient client = new HttpClient(); GetMethod request = new GetMethod(getControlServletURI() + PROTECTED_URI_PATH + "increment_the_counter"); request.addRequestHeader("X-Requested-With", "XMLHttpRequest"); client.executeMethod(request); int statusCode = request.getStatusCode(); assertEquals("Invalid status code. Status text: " + request.getStatusText(), HttpStatus.SC_FORBIDDEN, statusCode); // Get the value of the counter (via a non-protected path) to make sure it stayed at zero. request = new GetMethod(getControlServletURI() + ControlServlet.OPERATION_URI_SUFFIX_COUNTER_READ); request.addRequestHeader("X-Requested-With", "XMLHttpRequest"); client.executeMethod(request); statusCode = request.getStatusCode(); assertEquals("Invalid status code. Status text: " + request.getStatusText(), HttpStatus.SC_OK, statusCode); assertEquals("0", request.getResponseBodyAsString()); } /** * An authenticate request should not invoke the protected servlet. It should be handled only by the authenticator in both successful and invalid * authentication cases. * * @throws Exception */ public void testSuccessfulAuthenticateRequestDoesNotReachServlet() throws Exception { resetServletCounter(); Pair<String, String> userInfo = getDefaultUserAndPassword(); // Send a authentication request that we expect to succeed. HttpClient client = new HttpClient(); PostMethod authpost = new PostMethod(getControlServletURI() + EncryptedTokenAuthenticatorConstants.LOGIN_URI_SUFFIX); NameValuePair formUserid = new NameValuePair(EncryptedTokenAuthenticatorConstants.USERNAME_PARAMETER_NAME, userInfo.first); NameValuePair formPassword = new NameValuePair(EncryptedTokenAuthenticatorConstants.PASSWORD_PARAMETER_NAME, userInfo.second); authpost.setRequestBody(new NameValuePair[] { formUserid, formPassword }); authpost.addRequestHeader("X-Requested-With", "XMLHttpRequest"); authpost.setDoAuthentication(false); client.executeMethod(authpost); int statusCode = authpost.getStatusCode(); assertEquals("Invalid status code. Status text: " + authpost.getStatusText(), HttpStatus.SC_OK, statusCode); authpost.releaseConnection(); Cookie[] logoncookies = client.getState().getCookies(); boolean authenticated = false; for (int i = 0; i < logoncookies.length; i++) { if (logoncookies[i].getName().equals(EncryptedTokenAuthenticatorConstants.ANZO_TOKEN_COOKIE_NAME)) authenticated = true; } assertTrue("Expect a successful authentication.", authenticated); // Get the value of the counter (via a non-protected path) to make sure it stayed at zero, which would indicate the // servlet wasn't touched by the authenticate request. GetMethod request = new GetMethod(getControlServletURI() + ControlServlet.OPERATION_URI_SUFFIX_COUNTER_READ); request.addRequestHeader("X-Requested-With", "XMLHttpRequest"); client.executeMethod(request); statusCode = request.getStatusCode(); assertEquals("Invalid status code. Status text: " + request.getStatusText(), HttpStatus.SC_OK, statusCode); assertEquals("0", request.getResponseBodyAsString()); } /** * An authenticate request should not invoke the protected servlet. It should be handled only by the authenticator in both successful and invalid * authentication cases. * * @throws Exception */ public void testFailedAuthenticateRequestDoesNotReachServlet() throws Exception { resetServletCounter(); Pair<String, String> userInfo = getDefaultUserAndPassword(); // Send a authentication request that we expect to fail. HttpClient client = new HttpClient(); PostMethod authpost = new PostMethod(getControlServletURI() + EncryptedTokenAuthenticatorConstants.LOGIN_URI_SUFFIX); NameValuePair formUserid = new NameValuePair(EncryptedTokenAuthenticatorConstants.USERNAME_PARAMETER_NAME, userInfo.first); NameValuePair formPassword = new NameValuePair(EncryptedTokenAuthenticatorConstants.PASSWORD_PARAMETER_NAME, "anIncorrectPassword"); authpost.setRequestBody(new NameValuePair[] { formUserid, formPassword }); authpost.addRequestHeader("X-Requested-With", "XMLHttpRequest"); authpost.setDoAuthentication(false); client.executeMethod(authpost); int statusCode = authpost.getStatusCode(); assertEquals("Invalid status code. Status text: " + authpost.getStatusText(), HttpStatus.SC_FORBIDDEN, statusCode); authpost.releaseConnection(); Cookie[] logoncookies = client.getState().getCookies(); boolean authenticated = false; for (int i = 0; i < logoncookies.length; i++) { if (logoncookies[i].getName().equals(EncryptedTokenAuthenticatorConstants.ANZO_TOKEN_COOKIE_NAME)) authenticated = true; } assertFalse("Expect a failed authentication.", authenticated); // Get the value of the counter (via a non-protected path) to make sure it stayed at zero, which would indicate the // servlet wasn't touched by the authenticate request. GetMethod request = new GetMethod(getControlServletURI() + ControlServlet.OPERATION_URI_SUFFIX_COUNTER_READ); request.addRequestHeader("X-Requested-With", "XMLHttpRequest"); client.executeMethod(request); statusCode = request.getStatusCode(); assertEquals("Invalid status code. Status text: " + request.getStatusText(), HttpStatus.SC_OK, statusCode); assertEquals("0", request.getResponseBodyAsString()); } }