<?xml version="1.0"?>

<!--
 * ========================================================================
 * 
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * 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.
 * 
 * ========================================================================
-->

<document id="howto_security">

  <properties>
    <title>Testing secure code Howto</title>
  </properties>

  <body>

    <section title="Introduction to testing secure code">

      <p>
        Beginning with version 1.3, Cactus is able to unit test Servlet code
        that uses the Servlet Security API (<code>getRemoteUser()</code>,
        <code>isUserInRole()</code>, <code>getUserPrincipal()</code>).
        Cactus supports the BASIC and FORM authentication methods.
      </p>
      <p>
        The way to perform this is by securing a Servlet Redirector defined
        in your <code>web.xml</code> and then to specify user credentials
        in your <code>beginXXX()</code>, as defined below.
      </p>

      <note>
        The Cactus sample application demonstrates how to unit test everything
        that is explained here.
      </note>

    </section>

    <section title="Step 1: Passing credentials in beginXXX()">

      <p>
        Let's start with an example:
      </p>

<source><![CDATA[
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"));
}
]]></source>

      <p>
        There are several things to understand here:
      </p>
      <ul>
        <li>
          The Servlet that is called on the server side is the Cactus
          redirector servlet and thus we'll need to secure it in
          our <code>web.xml</code> (see step 2 below).
        </li>
        <li>
          <code>WebRequest.setRedirectorName()</code> is an API that lets you
          override the redirector defined in <code>cactus.properties</code>.
          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
          <code>ServletRedirectorSecure</code> redirector will be secured
          in step 2 below.
        </li>
        <li>
          <code>WebRequest.setAuthentication()</code> is used to pass
          credentials to the server. It takes an implementation of the 
          <code>Authentication</code> interface as argument. In this example,
          we pass in a <code>BasicAuthentication</code> which corresponds to
          the BASIC authentication method. Testing with form-based
          authentication just involves using the
          <code>FormAuthentication</code> class instead of
          <code>BasicAuthentication</code>.
        </li>
      </ul>

    </section>

    <section title="Step 2: Securing the Cactus Redirector">

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

<source><![CDATA[
[...]

<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>
]]></source>

    </section>

    <section title="Step 3: Map Users/Roles">

      <p>
        This step consists in defining authorized users and mapping them to the
        role defined in <code>web.xml</code> (e.g. in the example above, we have
        defined a <code>test</code> role).
      </p>

      <p>
        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:
      </p>
      <ul>
        <li>
          Create a <code>tomcat-users.xml</code> file that you put in your
          Tomcat configuration directory (where you have
          <code>server.xml</code> defined).
        </li>
      </ul>
      <p>
        Here is an example of <code>tomcat-users.xml</code> that matches the
        test we have defined in step 1:
      </p>

<source><![CDATA[
<tomcat-users>
  <user name="testuser" password="testpassword" roles="test" />
</tomcat-users>
]]></source>

    </section>

  </body>
</document>
