# Container Adapter Authentication

## Overview

Very early versions of Spring Security exclusively used Container Adapters for interfacing authentication with end users. Whilst this worked well, it required considerable time to support multiple container versions and the configuration itself was relatively time-consuming for developers. For this reason the HTTP Form Authentication and HTTP Basic Authentication approaches were developed, and are today recommended for almost all applications.

Container Adapters enable Spring Security to integrate directly with the containers used to host end user applications. This integration means that applications can continue to leverage the authentication and authorization capabilities built into containers (such as `isUserInRole()` and form-based or basic authentication), whilst benefiting from the enhanced security interception capabilities provided by Spring Security (it should be noted that Spring Security also offers `ContextHolderAwareRequestWrapper` to deliver `isUserInRole()` and similar Servlet Specification compatibility methods).

The integration between a container and Spring Security is achieved through an adapter. The adapter provides a container-compatible user authentication provider, and needs to return a container-compatible user object.

The adapter is instantiated by the container and is defined in a container-specific configuration file. The adapter then loads a Spring application context which defines the normal authentication manager settings, such as the authentication providers that can be used to authenticate the request. The application context is usually named `acegisecurity.xml` and is placed in a container-specific location.

Spring Security currently supports Jetty, Catalina (Tomcat), JBoss and Resin. Additional container adapters can easily be written

## Adapter Authentication Provider

As is always the case, the container adapter generated Authentication object still needs to be authenticated by an AuthenticationManager when requested to do so by the AbstractSecurityInterceptor. The AuthenticationManager needs to be certain the adapter-provided Authentication object is valid and was actually authenticated by a trusted adapter.

Adapters create Authentication objects which are immutable and implement the `AuthByAdapter` interface. These objects store the hash of a key that is defined by the adapter. This allows the Authentication object to be validated by the `AuthByAdapterProvider`. This authentication provider is defined as follows:

    <bean id="authByAdapterProvider"
            class="org.springframework.security.adapters.AuthByAdapterProvider">
    <property name="key"><value>my_password</value></property>
    </bean>

The key must match the key that is defined in the container-specific configuration file that starts the adapter. The `AuthByAdapterProvider` automatically accepts as valid any `AuthByAdapter` implementation that returns the expected hash of the key.

To reiterate, this means the adapter will perform the initial authentication using providers such as `DaoAuthenticationProvider`, returning an `AuthByAdapter` instance that contains a hash code of the key. Later, when an application calls a security interceptor managed resource, the `AuthByAdapter` instance in the SecurityContext in the SecurityContextHolder will be tested by the application's `AuthByAdapterProvider`. There is no requirement for additional authentication providers such as `DaoAuthenticationProvider` within the application-specific application context, as the only type of Authentication instance that will be presented by the application is from the container adapter.

Classloader issues are frequent with containers and the use of container adapters illustrates this further. Each container requires a very specific configuration. The installation instructions are provided below. Once installed, please take the time to try the sample application to ensure your container adapter is properly configured.

When using container adapters with the `DaoAuthenticationProvider`, ensure you set its `forcePrincipalAsString` property to `true`.

## Jetty

The following was tested with Jetty 4.2.18.

`$JETTY_HOME` refers to the root of your Jetty installation.

Edit your `$JETTY_HOME/etc/jetty.xml` file so the `<Configure class>` section has a new `addRealm` call:

    <Call name="addRealm">
    <Arg>
      <New class="org.springframework.security.adapters.jetty.JettySpringSecurityUserRealm">
        <Arg>Spring Powered Realm</Arg>
        <Arg>my_password</Arg>
        <Arg>etc/acegisecurity.xml</Arg>
      </New>
    </Arg>
    </Call>

Copy `acegisecurity.xml` into `$JETTY_HOME/etc`.

Copy the following files into `$JETTY_HOME/ext`:

- `aopalliance.jar`

- `commons-logging.jar`

- `spring.jar`

- `acegi-security-jetty-XX.jar`

- `commons-codec.jar`

- `burlap.jar`

- `hessian.jar`

None of the above JAR files (or `acegi-security-XX.jar`) should be in your application's `WEB-INF/lib`. The realm name indicated in your `web.xml` does matter with Jetty. The `web.xml` must express the same `<realm-name>` as your `jetty.xml` (in the example above, "Spring Powered Realm").

## JBoss

The following was tested with JBoss 3.2.6.

`$JBOSS_HOME` refers to the root of your JBoss installation.

There are two different ways of making spring context available to the Jboss integration classes.

The first approach is by editing your `$JBOSS_HOME/server/your_config/conf/login-config.xml` file so that it contains a new entry under the `<Policy>` section:

    <application-policy name = "SpringPoweredRealm">
    <authentication>
      <login-module code = "org.springframework.security.adapters.jboss.JbossSpringSecurityLoginModule"
            flag = "required">
        <module-option name = "appContextLocation">acegisecurity.xml</module-option>
        <module-option name = "key">my_password</module-option>
     </login-module>
    </authentication>
    </application-policy>

Copy `acegisecurity.xml` into `$JBOSS_HOME/server/your_config/conf`.

In this configuration `acegisecurity.xml` contains the spring context definition including all the authentication manager beans. You have to bear in mind though, that SecurityContext is created and destroyed on each login request, so the login operation might become costly. Alternatively, the second approach is to use Spring singleton capabilities through `org.springframework.beans.factory.access.SingletonBeanFactoryLocator`. The required configuration for this approach is:

    <application-policy name = "SpringPoweredRealm">
    <authentication>
      <login-module code = "org.springframework.security.adapters.jboss.JbossSpringSecurityLoginModule"
            flag = "required">
        <module-option name = "singletonId">springRealm</module-option>
        <module-option name = "key">my_password</module-option>
        <module-option name = "authenticationManager">authenticationManager</module-option>
     </login-module>
    </authentication>
    </application-policy>

In the above code fragment, `authenticationManager` is a helper property that defines the expected name of the AuthenticationManager in case you have several defined in the IoC container. The `singletonId` property references a bean defined in a `beanRefFactory.xml` file. This file needs to be available from anywhere on the JBoss classpath, including `$JBOSS_HOME/server/your_config/conf`. The `beanRefFactory.xml` contains the following declaration:

    <beans>
    <bean id="springRealm" singleton="true" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext">
    <constructor-arg>
      <list>
        <value>acegisecurity.xml</value>
      </list>
    </constructor-arg>
    </bean>
    </beans>

Finally, irrespective of the configuration approach you need to copy the following files into `$JBOSS_HOME/server/your_config/lib`:

- `aopalliance.jar`

- `spring.jar`

- `acegi-security-jboss-XX.jar`

- `commons-codec.jar`

- `burlap.jar`

- `hessian.jar`

None of the above JAR files (or `acegi-security-XX.jar`) should be in your application's `WEB-INF/lib`. The realm name indicated in your `web.xml` does not matter with JBoss. However, your web application's `WEB-INF/jboss-web.xml` must express the same `<security-domain>` as your `login-config.xml`. For example, to match the above example, your `jboss-web.xml` would look like this:

    <jboss-web>
    <security-domain>java:/jaas/SpringPoweredRealm</security-domain>
    </jboss-web>

JBoss is a widely-used container adapter (mostly due to the need to support legacy EJBs), so please let us know if you have any difficulties.

## Resin

The following was tested with Resin 3.0.6.

`$RESIN_HOME` refers to the root of your Resin installation.

Resin provides several ways to support the container adapter. In the instructions below we have elected to maximise consistency with other container adapter configurations. This will allow Resin users to simply deploy the sample application and confirm correct configuration. Developers comfortable with Resin are naturally able to use its capabilities to package the JARs with the web application itself, and/or support single sign-on.

Copy the following files into `$RESIN_HOME/lib`:

- `aopalliance.jar`

- `commons-logging.jar`

- `spring.jar`

- `acegi-security-resin-XX.jar`

- `commons-codec.jar`

- `burlap.jar`

- `hessian.jar`

Unlike the container-wide `acegisecurity.xml` files used by other container adapters, each Resin web application will contain its own `WEB-INF/resin-acegisecurity.xml` file. Each web application will also contain a `resin-web.xml` file which Resin uses to start the container adapter:

    <web-app>
    <authenticator>
    <type>org.springframework.security.adapters.resin.ResinAcegiAuthenticator</type>
    <init>
      <app-context-location>WEB-INF/resin-acegisecurity.xml</app-context-location>
      <key>my_password</key>
    </init>
    </authenticator>
    </web-app>

With the basic configuration provided above, none of the JAR files listed (or `acegi-security-XX.jar`) should be in your application's `WEB-INF/lib`. The realm name indicated in your `web.xml` does not matter with Resin, as the relevant authentication class is indicated by the `<authenticator>` setting

## Tomcat

The following was tested with Jakarta Tomcat 4.1.30 and 5.0.19.

`$CATALINA_HOME` refers to the root of your Catalina (Tomcat) installation.

Edit your `$CATALINA_HOME/conf/server.xml` file so the `<Engine>` section contains only one active `<Realm>` entry. An example realm entry:

          <Realm
            className="org.springframework.security.adapters.catalina.CatalinaSpringSecurityUserRealm"
            appContextLocation="conf/acegisecurity.xml"
             key="my_password" />

Be sure to remove any other `<Realm>` entry from your `<Engine>` section.

Copy `acegisecurity.xml` into `$CATALINA_HOME/conf`.

Copy `spring-security-catalina-XX.jar` into `$CATALINA_HOME/server/lib`.

Copy the following files into `$CATALINA_HOME/common/lib`:

- `aopalliance.jar`

- `spring.jar`

- `commons-codec.jar`

- `burlap.jar`

- `hessian.jar`

None of the above JAR files (or `spring-security-XX.jar`) should be in your application's `WEB-INF/lib`. The realm name indicated in your `web.xml` does not matter with Catalina.

We have received reports of problems using this Container Adapter with Mac OS X. A work-around is to use a script such as follows:

    #!/bin/sh
    export CATALINA_HOME="/Library/Tomcat"
    export JAVA_HOME="/Library/Java/Home"
    cd /
    $CATALINA_HOME/bin/startup.sh

Finally, restart Tomcat.