2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

Introduction to testing secure code

Beginning with version 1.3, Cactus is able to unit test Servlet code that uses the Servlet Security API (getRemoteUser(), isUserInRole(), getUserPrincipal()). Cactus supports the BASIC and FORM authentication methods.

The way to perform this is by securing a Servlet Redirector defined in your web.xml and then to specify user credentials in your beginXXX(), as defined below.

The Cactus sample application demonstrates how to unit test everything that is explained here.

Step 1: Passing credentials in beginXXX()

Let's start with an example:

public void beginBasicAuthentication(WebRequest theRequest)
{
    theRequest.setRedirectorName("ServletRedirectorSecure");
    theRequest.setAuthentication(
        new BasicAuthentication("testuser", "testpassword"));
}

public void testBasicAuthentication()
{
    assertEquals("testuser", request.getUserPrincipal().getName());
    assertEquals("testuser", request.getRemoteUser());
    assertTrue("User not in 'test' role", request.isUserInRole("test"));
}

There are several things to understand here:

  • The Servlet that is called on the server side is the Cactus redirector servlet and thus we'll need to secure it in our web.xml (see step 2 below).
  • WebRequest.setRedirectorName() is an API that lets you override the redirector defined in cactus.properties. This is needed here because we want to test both code that is not secured (i.e. for which we don't want to have to pass credentials) and code that is secured and thus we need 2 redirectors. The ServletRedirectorSecure redirector will be secured in step 2 below.
  • WebRequest.setAuthentication() is used to pass credentials to the server. It takes an implementation of the Authentication interface as argument. In this example, we pass in a BasicAuthentication which corresponds to the BASIC authentication method. Testing with form-based authentication just involves using the FormAuthentication class instead of BasicAuthentication.

Step 2: Securing the Cactus Redirector

If you're using the Cactus Ant tasks to execute your Cactus tests, please check the Cactifywar task page as the configuration below is only required for manual configuration and is handled automatically by the Cactifywar task. All calls to the server side go through the Cactus Servlet Redirector and thus it is that servlet that needs to be secured in web.xml. The required modifications to web.xml are as follows (example):
[...]

<web-app>

  <servlet>
    <servlet-name>ServletRedirector</servlet-name>
    <servlet-class>org.apache.cactus.server.ServletTestRedirector</servlet-class>
  </servlet>

  <servlet>
    <servlet-name>ServletRedirectorSecure</servlet-name>
    <servlet-class>org.apache.cactus.server.ServletTestRedirector</servlet-class>
  </servlet>

  [...]

  <servlet-mapping>
    <servlet-name>ServletRedirector</servlet-name>
    <url-pattern>/ServletRedirector</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>ServletRedirectorSecure</servlet-name>
    <url-pattern>/ServletRedirectorSecure</url-pattern>
  </servlet-mapping>

  [...]

  <!-- Start Authentication -->

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>SecurityRestriction</web-resource-name>
      <description>Protect the Cactus redirector servlet.</description>
      <url-pattern>/ServletRedirectorSecure</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
      <description>Authorized Users Group</description>
      <role-name>test</role-name>
    </auth-constraint>
    <user-data-constraint>
      <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
  </security-constraint>

  <login-config>
    <auth-method>BASIC</auth-method>
  </login-config>

  <security-role>
    <description>Test role</description>
    <role-name>test</role-name>
  </security-role>

  <!-- End Authentication -->

</web-app>

Step 3: Map Users/Roles

This step consists in defining authorized users and mapping them to the role defined in web.xml (e.g. in the example above, we have defined a test role). This step is completely container-dependent and there is no standard way of doing it. You'll have to learn how to do it for your container. For example, here is how you would do it for Tomcat 4.0:
  • Create a tomcat-users.xml file that you put in your Tomcat configuration directory (where you have server.xml defined).
Here is an example of tomcat-users.xml that matches the test we have defined in step 1:
<tomcat-users>
  <user name="testuser" password="testpassword" roles="test" />
</tomcat-users>