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
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
.
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").
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.
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
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.