spring-security/doc/docbook/acegi.xml

6046 lines
313 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!--
* ========================================================================
*
* Copyright 2004 Acegi Technology Pty Limited
*
* 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.
*
* ========================================================================
-->
<book>
<bookinfo>
<title>Acegi Security</title>
<subtitle>Reference Documentation</subtitle>
<releaseinfo>1.0.3</releaseinfo>
<authorgroup>
<author>
<firstname>Ben</firstname>
<surname>Alex</surname>
</author>
</authorgroup>
</bookinfo>
<toc></toc>
<preface id="preface">
<title>Preface</title>
<para>Acegi Security provides a comprehensive security solution for
J2EE-based enterprise software applications. As you will discover as you
venture through this reference guide, we have tried to provide you a
useful and highly configurable security system.</para>
<para>Security is an ever-moving target, and it's important to pursue a
comprehensive, system-wide approach. In security circles we encourage you
to adopt "layers of security", so that each layer tries to be as secure as
possible in its own right, with successive layers providing additional
security. The "tighter" the security of each layer, the more robust and
safe your application will be. At the bottom level you'll need to deal
with issues such as transport security and system identification, in order
to mitigate man-in-the-middle attacks. Next you'll generally utilise
firewalls, perhaps with VPNs or IP security to ensure only authorised
systems can attempt to connect. In corporate environments you may deploy a
DMZ to separate public-facing servers from backend database and
application servers. Your operating system will also play a critical part,
addressing issues such as running processes as non-privileged users and
maximising file system security. An operating system will usually also be
configured with its own firewall. Hopefully somewhere along the way you'll
be trying to prevent denial of service and brute force attacks against the
system. An intrusion detection system will also be especially useful for
monitoring and responding to attacks, with such systems able to take
protective action such as blocking offending TCP/IP addresses in
real-time. Moving to the higher layers, your Java Virtual Machine will
hopefully be configured to minimize the permissions granted to different
Java types, and then your application will add its own problem
domain-specific security configuration. Acegi Security makes this latter
area - application security - much easier.</para>
<para>Of course, you will need to properly address all security layers
mentioned above, together with managerial factors that encompass every
layer. A non-exhaustive list of such managerial factors would include
security bulletin monitoring, patching, personnel vetting, audits, change
control, engineering management systems, data backup, disaster recovery,
performance benchmarking, load monitoring, centralised logging, incident
response procedures etc.</para>
<para>With Acegi Security being focused on helping you with the enterprise
application security layer, you will find that there are as many different
requirements as there are business problem domains. A banking application
has different needs from an ecommerce application. An ecommerce
application has different needs from a corporate sales force automation
tool. These custom requirements make application security interesting,
challenging and rewarding.</para>
<para>This reference guide has been largely restructured for the 1.0.0
release of Acegi Security. Please read Part I, <link
linkend="overall-architecture">Overall Architecture</link>, in its
entirety. The remaining parts of the reference guide are structured in a
more traditional reference style, designed to be read on an as-required
basis.</para>
<para>We hope that you find this reference guide useful, and we welcome
your feedback and <link linkend="jira">suggestions</link>.</para>
<para>Finally, welcome to the Acegi Security <link
linkend="community">community</link>.</para>
</preface>
<part id="overall-architecture">
<title>Overall Architecture</title>
<partintro>
<para>Like most software, Acegi Security has certain central interfaces,
classes and conceptual abstractions that are commonly used throughout
the framework. In this part of the reference guide we will introduce
Acegi Security, before examining these central elements that are
necessary to successfully planning and executing an Acegi Security
integration.</para>
</partintro>
<chapter id="introduction">
<title>Introduction</title>
<sect1 id="what-is-acegi-security">
<title>What is Acegi Security?</title>
<para>Acegi Security provides comprehensive security services for
J2EE-based enterprise software applications. There is a particular
emphasis on supporting projects built using The Spring Framework,
which is the leading J2EE solution for enterprise software
development. If you're not using Spring for developing enterprise
applications, we warmly encourage you to take a closer look at it.
Some familiarity with Spring - and in particular dependency injection
principles - will help you get up to speed with Acegi Security more
easily.</para>
<para>People use Acegi Security for many reasons, but most are drawn
to the project after finding the security features of J2EE's Servlet
Specification or EJB Specification lack the depth required for typical
enterprise application scenarios. Whilst mentioning these standards,
it's important to recognise that they are not portable at a WAR or EAR
level. Therefore, if you switch server environments, it is typically a
lot of work to reconfigure your application's security in the new
target environment. Using Acegi Security overcomes these problems, and
also brings you dozens of other useful, entirely customisable security
features.</para>
<para>As you probably know, security comprises two major operations.
The first is known as "authentication", which is the process of
establishing a principal is who they claim to be. A "principal"
generally means a user, device or some other system which can perform
an action in your application. "Authorization" refers to the process
of deciding whether a principal is allowed to perform an action in
your application. To arrive at the point where an authorization
decision is needed, the identity of the principal has already been
established by the authentication process. These concepts are common,
and not at all specific to Acegi Security.</para>
<para>At an authentication level, Acegi Security supports a wide range
of authentication models. Most of these authentication models are
either provided by third parties, or are developed by relevant
standards bodies such as the Internet Engineering Task Force. In
addition, Acegi Security provides its own set of authentication
features. Specifically, Acegi Security currently supports
authentication with all of these technologies:</para>
<itemizedlist spacing="compact">
<listitem>
<para>HTTP BASIC authentication headers (an IEFT RFC-based
standard)</para>
</listitem>
<listitem>
<para>HTTP Digest authentication headers (an IEFT RFC-based
standard)</para>
</listitem>
<listitem>
<para>HTTP X.509 client certificate exchange (an IEFT RFC-based
standard)</para>
</listitem>
<listitem>
<para>LDAP (a very common approach to cross-platform
authentication needs, especially in large environments)</para>
</listitem>
<listitem>
<para>Form-based authentication (for simple user interface
needs)</para>
</listitem>
<listitem>
<para>Computer Associates Siteminder</para>
</listitem>
<listitem>
<para>JA-SIG Central Authentication Service (otherwise known as
CAS, which is a popular open source single sign on system)</para>
</listitem>
<listitem>
<para>Transparent authentication context propagation for Remote
Method Invocation (RMI) and HttpInvoker (a Spring remoting
protocol)</para>
</listitem>
<listitem>
<para>Automatic "remember-me" authentication (so you can tick a
box to avoid re-authentication for a predetermined period of
time)</para>
</listitem>
<listitem>
<para>Anonymous authentication (allowing every call to
automatically assume a particular security identity)</para>
</listitem>
<listitem>
<para>Run-as authentication (which is useful if one call should
proceed with a different security identity)</para>
</listitem>
<listitem>
<para>Java Authentication and Authorization Service (JAAS)</para>
</listitem>
<listitem>
<para>Container integration with JBoss, Jetty, Resin and Tomcat
(so you can still use Container Manager Authentication if
desired)</para>
</listitem>
<listitem>
<para>Your own authentication systems (see below)</para>
</listitem>
</itemizedlist>
<para>Many independent software vendors (ISVs) adopt Acegi Security
because of this rich choice of authentication models. Doing so allows
them to quickly integrate their solutions with whatever their end
clients need, without undertaking a lot of engineering or requiring
the client to change their environment. If none of the above
authentication mechanisms suit your needs, Acegi Security is an open
platform and it is quite simple to write your own authentication
mechanism. Many corporate users of Acegi Security need to integrate
with "legacy" systems that don't follow any particular security
standards, and Acegi Security is happy to "play nicely" with such
systems.</para>
<para>Sometimes the mere process of authentication isn't enough.
Sometimes you need to also differentiate security based on the way a
principal is interacting with your application. For example, you might
want to ensure requests only arrive over HTTPS, in order to protect
passwords from eavesdropping or end users from man-in-the-middle
attacks. Or, you might want to ensure that an actual human being is
making the requests and not some robot or other automated process.
This is especially helpful to protect password recovery processes from
brute force attacks, or simply to make it harder for people to
duplicate your application's key content. To help you achieve these
goals, Acegi Security fully supports automatic "channel security",
together with JCaptcha integration for human user detection.</para>
<para>Irrespective of how authentication was undertaken, Acegi
Security provides a deep set of authorization capabilities. There are
three main areas of interest in respect of authorization, these being
authorizing web requests, authorizing methods can be invoked, and
authorizing access to individual domain object instances. To help you
understand the differences, consider the authorization capabilities
found in the Servlet Specification web pattern security, EJB Container
Managed Security and file system security respectively. Acegi Security
provides deep capabilities in all of these important areas, which
we'll explore later in this reference guide.</para>
</sect1>
<sect1 id="history">
<title>History</title>
<para>Acegi Security began in late 2003, when a question was posed on
the Spring Developers' mailing list asking whether there had been any
consideration given to a Spring-based security implementation. At the
time the Spring community was relatively small (especially by today's
size!), and indeed Spring itself had only existed as a SourceForge
project from early 2003. The response to the question was that it was
a worthwhile area, although a lack of time currently prevented its
exploration.</para>
<para>With that in mind, a simple security implementation was built
and not released. A few weeks later another member of the Spring
community inquired about security, and at the time this code was
offered to them. Several other requests followed, and by January 2004
around twenty people were using the code. These pioneering users were
joined by others who suggested a SourceForge project was in order,
which was duly established in March 2004.</para>
<para>In those early days, the project didn't have any of its own
authentication modules. Container Managed Security was relied upon for
the authentication process, with Acegi Security instead focusing on
authorization. This was suitable at first, but as more and more users
requested additional container support, the fundamental limitation of
container-specific authentication realm interfaces was experienced.
There was also a related issue of adding new JARs to the container's
classpath, which was a common source of end user confusion and
misconfiguration.</para>
<para>Acegi Security-specific authentication services were
subsequently introduced. Around a year later, the Acegi Security
became an official Spring Framework subproject. The 1.0.0 final
release was published in May 2006 - after more than two and a half
years of active use in numerous production software projects and many
hundreds of improvements and community contributions.</para>
<para>Today Acegi Security enjoys a strong and active open source
community. There are thousands of messages about Acegi Security on the
support forums. Fourteen developers work on the code itself, with an
active community who also regularly share patches and support their
peers.</para>
</sect1>
<sect1 id="release-numbering">
<title>Release Numbering</title>
<para>It is useful to understand how Acegi Security release numbers
work, as it will help you identify the effort (or lack thereof)
involved in migrating to future releases of the project. Officially,
we use the Apache Portable Runtime Project versioning guidelines,
which can be viewed at
<literal>http://apr.apache.org/versioning.html</literal>. We quote the
introduction contained on that page for your convenience:</para>
<para><quote>Versions are denoted using a standard triplet of
integers: MAJOR.MINOR.PATCH. The basic intent is that MAJOR versions
are incompatible, large-scale upgrades of the API. MINOR versions
retain source and binary compatibility with older minor versions, and
changes in the PATCH level are perfectly compatible, forwards and
backwards.</quote></para>
</sect1>
</chapter>
<chapter id="technical-overview">
<title>Technical Overview</title>
<sect1 id="runtime-environment">
<title>Runtime Environment</title>
<para>Acegi Security is written to execute within a standard Java 1.3
Runtime Environment. It also supports Java 5.0, although the Java
types which are specific to this release are packaged in a separate
package with the suffix "tiger" in their JAR filename. As Acegi
Security aims to operate in a self-contained manner, there is no need
to place any special configuration files into your Java Runtime
Environment. In particular, there is no need to configure a special
Java Authentication and Authorization Service (JAAS) policy file or
place Acegi Security into common classpath locations.</para>
<para>Similarly, if you are using an EJB Container or Servlet
Container there is no need to put any special configuration files
anywhere, nor include Acegi Security in a server classloader.</para>
<para>This above design offers maximum deployment time flexibility, as
you can simply copy your target artifact (be it a JAR, WAR or EAR)
from one system to another and it will immediately work.</para>
</sect1>
<sect1 id="shared-components">
<title>Shared Components</title>
<para>Let's explore some of the most important shared components in
Acegi Security. Components are considered "shared" if they are central
to the framework and the framework cannot operate without them. These
Java types represent the building blocks of the remaining system, so
it's important to understand that they're there, even if you don't
need to directly interact with them.</para>
<para>The most fundamental object is
<literal>SecurityContextHolder</literal>. This is where we store
details of the present security context of the application, which
includes details of the principal currently using the application. By
default the <literal>SecurityContextHolder</literal> uses a
<literal>ThreadLocal</literal> to store these details, which means
that the security context is always available to methods in the same
thread of execution, even if the security context is not explicitly
passed around as an argument those methods. Using a
<literal>ThreadLocal</literal> in this way is quite safe if care is
taken to clear the thread after the present principal's request is
processed. Of course, Acegi Security takes care of for you
automatically so there is no need to worry about it.</para>
<para>Some applications aren't entirely suitable for using a
<literal>ThreadLocal</literal>, because of the specific way they work
with threads. For example, a Swing client might want all threads in a
Java Virtual Machine to use the same security context. For this
situation you would use the
<literal>SecurityContextHolder.MODE_GLOBAL</literal>. Other
applications might want to have threads spawned by the secure thread
also assume the same security identity. This is achieved by using
<literal>SecurityContextHolder.MODE_INHERITABLETHREADLOCAL</literal>.
You can change the mode from the default
<literal>SecurityContextHolder.MODE_THREADLOCAL</literal> in two ways.
The first is to set a system property. Alternatively, call a static
method on <literal>SecurityContextHolder</literal>. Most applications
won't need to change from the default, but if you do, take a look at
the JavaDocs for <literal>SecurityContextHolder</literal> to learn
more.</para>
<para>Inside the <literal>SecurityContextHolder</literal> we store
details of the principal currently interacting with the application.
Acegi Security uses an <literal>Authentication</literal> object to
represent this information. Whilst you won't normally need to create
an <literal>Authentication</literal> object yourself, it is fairly
common for users to query the <literal>Authentication</literal>
object. You can use the following code block - from anywhere in your
application - to do this:</para>
<programlisting>Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (obj instanceof UserDetails) {
String username = ((UserDetails)obj).getUsername();
} else {
String username = obj.toString();
}</programlisting>
<para>The above code introduces a number of interesting relationships
and key objects. First, you will notice that there is an intermediate
object between <literal>SecurityContextHolder</literal> and
<literal>Authentication</literal>. The
<literal>SecurityContextHolder.getContext()</literal> method is
actually returning a <literal>SecurityContext</literal>. Acegi
Security uses a few different <literal>SecurityContext</literal>
implementations, such as if we need to store special information
related to a request that is not principal-specific. A good example of
this is our JCaptcha integration, which needs to know whether the
current request came from a human user or not. Because such a decision
has nothing at all to do with the principal the request may or may not
be authenticated as, we store it in the
<literal>SecurityContext</literal>.</para>
<para>Another item to note from the above code fragment is that you
can obtain a principal from the <literal>Authentication</literal>
object. The principal is just an <literal>Object</literal>. Most of
the time this can be cast into a <literal>UserDetails</literal>
object. <literal>UserDetails</literal> is a central interface in Acegi
Security. It represents a principal, but in an extensible and
application-specific way. Think of <literal>UserDetails</literal> as
the adapter between your own user database and what Acegi Security
needs inside the <literal>SecurityContextHolder</literal>. Being a
representation of something from your own user database, quite often
you will cast the <literal>UserDetails</literal> to the original
object that your application provided, so you can call
business-specific methods (like <literal>getEmail()</literal>,
<literal>getEmployeeNumber()</literal> and so on).</para>
<para>By now you're probably wondering, so when do I provide a
<literal>UserDetails</literal> object? How do I do that? I thought you
said this thing was declarative and I didn't need to write any Java
code - what gives? The short answer is that there is a special
interface called <literal>UserDetailsService</literal>. The only
method on this interface accepts a <literal>String</literal>-based
username argument and returns a <literal>UserDetails</literal>. Most
authentication providers that ship with Acegi Security delegate to a
<literal>UserDetailsService</literal> as part of the authentication
process. The <literal>UserDetailsService</literal> is used to build
the <literal>Authentication</literal> object that is stored in the
<literal>SecurityContextHolder</literal>. The good news is that we
provide a number of <literal>UserDetailsService</literal>
implementations, including one that uses an in-memory map and another
that uses JDBC. Most users tends to write their own, though, with such
implementations often simply sitting on top of an existing Data Access
Object (DAO) that represents their employees, customers, or other
users of the enterprise application. Remember the advantage that
whatever your UserDetailsService returns can always be obtained from
the <literal>SecurityContextHolder</literal>, as per the above code
fragment.</para>
<para>Besides the principal, another important method provided by
<literal>Authentication</literal> is
<literal>getAuthorities(</literal>). This method provides an array of
<literal>GrantedAuthority</literal> objects. A
<literal>GrantedAuthority</literal> is, not surprisingly, an authority
that is granted to the principal. Such authorities are usually
"roles", such as <literal>ROLE_ADMINISTRATOR</literal> or
<literal>ROLE_HR_SUPERVISOR</literal>. These roles are later on
configured for web authorization, method authorization and domain
object authorization. Other parts of Acegi Security are capable of
interpreting these authorities, and expect them to be present. You
will usually return <literal>GrantedAuthority</literal> objects from
the <literal>UserDetailsService</literal>.</para>
<para>Usually the <literal>GrantedAuthority</literal> objects are
application-wide permissions. They are not specific to a given domain
object. Thus, you wouldn't likely have a
<literal>GrantedAuthority</literal> to represent a permission to
<literal>Employee</literal> object number 54, because if there are
thousands of such authorities you would quickly run out of memory (or,
at the very least, cause the application to take a long time to
authenticate a user). Of course, Acegi Security is expressly designed
to handle this common requirement, but you'd instead use the project's
domain object security capabilities for this purpose.</para>
<para>Last but not least, sometimes you will need to store the
<literal>SecurityContext</literal> between HTTP requests. Other times
the principal will re-authenticate on every request, although most of
the time it will be stored. The
<literal>HttpSessionContextIntegrationFilter</literal> is responsible
for storing a <literal>SecurityContext</literal> between HTTP
requests. As suggested by the name of the class, the
<literal>HttpSession</literal> is used to store this information. You
should never interact directly with the <literal>HttpSession</literal>
for security purposes. There is simply no justification for doing so -
always use the <literal>SecurityContextHolder</literal>
instead.</para>
<para>Just to recap, the major building blocks of Acegi Security
are:</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>SecurityContextHolder</literal>, to provide any
type access to the <literal>SecurityContext</literal>.</para>
</listitem>
<listitem>
<para><literal>SecurityContext</literal>, to hold the
<literal>Authentication</literal> and possibly request-specific
security information.</para>
</listitem>
<listitem>
<para><literal>HttpSessionContextIntegrationFilter</literal>, to
store the <literal>SecurityContext</literal> in the
<literal>HttpSession</literal> between web requests.</para>
</listitem>
<listitem>
<para><literal>Authentication</literal>, to represent the
principal in an Acegi Security-specific manner.</para>
</listitem>
<listitem>
<para><literal>GrantedAuthority</literal>, to reflect the
application-wide permissions granted to a principal.</para>
</listitem>
<listitem>
<para><literal>UserDetails</literal>, to provide the necessary
information to build an Authentication object from your
application's DAOs.</para>
</listitem>
<listitem>
<para><literal>UserDetailsService</literal>, to create a
<literal>UserDetails</literal> when passed in a
<literal>String</literal>-based username (or certificate ID or
alike).</para>
</listitem>
</itemizedlist>
<para>Now that you've gained an understanding of these repeatedly-used
components, let's take a closer look at the process of
authentication.</para>
</sect1>
<sect1 id="common-authentication">
<title>Authentication</title>
<para>As mentioned in the beginning of this reference guide, Acegi
Security can participate in many different authentication
environments. Whilst we recommend people use Acegi Security for
authentication and not integrate with existing Container Managed
Authentication, it is nevertheless supported - as is integrating with
your own proprietary authentication system. Let's first explore
authentication from the perspective of Acegi Security managing web
security entirely on its own, which is illustrative of the most
complex and most common situation.</para>
<para>Consider a typical web application's authentication
process:</para>
<orderedlist>
<listitem>
<para>You visit the home page, and click on a link.</para>
</listitem>
<listitem>
<para>A request goes to the server, and the server decides that
you've asked for a protected resource.</para>
</listitem>
<listitem>
<para>As you're not presently authenticated, the server sends back
a response indicating that you must authenticate. The response
will either be a HTTP response code, or a redirect to a particular
web page.</para>
</listitem>
<listitem>
<para>Depending on the authentication mechanism, your browser will
either redirect to the specific web page so that you can fill out
the form, or the browser will somehow retrieve your identity (eg a
BASIC authentication dialogue box, a cookie, a X509 certificate
etc).</para>
</listitem>
<listitem>
<para>The browser will send back a response to the server. This
will either be a HTTP POST containing the contents of the form
that you filled out, or a HTTP header containing your
authentication details.</para>
</listitem>
<listitem>
<para>Next the server will decide whether or not the presented
credentials are valid. If they're valid, the next step will
happen. If they're invalid, usually your browser will be asked to
try again (so you return to step two above).</para>
</listitem>
<listitem>
<para>The original request that you made to cause the
authentication process will be retried. Hopefully you've
authenticated with sufficient granted authorities to access the
protected resource. If you have sufficient access, the request
will be successful. Otherwise, you'll receive back a HTTP error
code 403, which means "forbidden".</para>
</listitem>
</orderedlist>
<para>Acegi Security has distinct classes responsible for most of the
steps described above. The main participants (in the order that they
are used) are the <literal>ExceptionTranslationFilter</literal>, an
<literal>AuthenticationEntryPoint</literal>, an authentication
mechanism, and an <literal>AuthenticationProvider</literal>.</para>
<para><literal>ExceptionTranslationFilter</literal> is an Acegi
Security filter that has responsibility for detecting any Acegi
Security exceptions that are thrown. Such exceptions will generally be
thrown by an <literal>AbstractSecurityInterceptor</literal>, which is
the main provider of authorization services. We will discuss
<literal>AbstractSecurityInterceptor</literal> in the next section,
but for now we just need to know that it produces Java exceptions and
knows nothing about HTTP or how to go about authenticating a
principal. Instead the <literal>ExceptionTranslationFilter</literal>
offers this service, with specific responsibility for either returning
error code 403 (if the principal has been authenticated and therefore
simply lacks sufficient access - as per step seven above), or
launching an <literal>AuthenticationEntryPoint</literal> (if the
principal has not been authenticated and therefore we need to go
commence step three).</para>
<para>The <literal>AuthenticationEntryPoint</literal> is responsible
for step three in the above list. As you can imagine, each web
application will have a default authentication strategy (well, this
can be configured like nearly everything else in Acegi Security, but
let's keep it simple for now). Each major authentication system will
have its own <literal>AuthenticationEntryPoint</literal>
implementation, which takes actions such as described in step
three.</para>
<para>After your browser decides to submit your authentication
credentials (either as a HTTP form post or HTTP header) there needs to
be something on the server that "collects" these authentication
details. By now we're at step six in the above list. In Acegi Security
was have a special name for the function of collecting authentication
details from a user agent (usually a web browser), and that name is
"authentication mechanism". After the authentication details are
collected from the user agent, an "<literal>Authentication</literal>
request" object is built and then presented to an
AuthenticationProvider.</para>
<para>The last played in the Acegi Security authentication process is
an <literal>AuthenticationProvider</literal>. Quite simply, it is
responsible for taking an <literal>Authentication</literal> request
object and deciding whether or not it is valid. The provider will
either throw an exception, or return a fully populated
<literal>Authentication</literal> object. Remember our good friends,
<literal>UserDetails</literal> and
<literal>UserDetailsService</literal>? If not, head back to the
previous section and refresh your memory. Most
<literal>AuthenticationProvider</literal>s will ask a
<literal>UserDetailsService</literal> to provide a
<literal>UserDetails</literal> object. As mentioned earlier, most
application will provide their own
<literal>UserDetailsService</literal>, although some will be able to
use the JDBC or in-memory implementation that ships with Acegi
Security. The resultant <literal>UserDetails</literal> object - and
particularly the <literal>GrantedAuthority[]</literal>s contained
within the <literal>UserDetails</literal> object - will be used when
building the fully populated <literal>Authentication</literal>
object.</para>
<para>After the authentication mechanism receives back the
fully-populated <literal>Authentication</literal> object, it will deem
the request valid, put the <literal>Authentication</literal> into the
<literal>SecurityContextHolder</literal>, and cause the original
request to be retried (step seven above). If, on the other hand, the
<literal>AuthenticationProvider</literal> rejected the request, the
authentication mechanism will ask the user agent to retry (step two
above).</para>
<para>Whilst this describes the typical authentication workflow, the
good news is that Acegi Security doesn't mind how you put an
<literal>Authentication</literal> inside the
<literal>SecurityContextHolder</literal>. The only critical
requirement is that the <literal>SecurityContextHolder</literal>
contains an <literal>Authentication</literal> that represents a
principal before the <literal>AbstractSecurityInterceptor</literal>
needs to authorize a request.</para>
<para>You can (and many users do) write their own filters or MVC
controllers to provide interoperability with authentication systems
that are not based on Acegi Security. For example, you might be using
Container Managed Authentication which makes the current user
available from a ThreadLocal or JNDI location. Or you might work for a
company that has a legacy proprietary authentication system, which is
a corporate "standard" over which you have little control. In such
situations it's quite easy to get Acegi Security to work, and still
provide authorization capabilities. All you need to do is write a
filter (or equivalent) that reads the third-party user information
from a location, build an Acegi Security-specific Authentication
object, and put it onto the SecurityContextHolder. It's quite easy to
do this, and a fully-supported integration approach.</para>
</sect1>
<sect1 id="secure-objects">
<title>Secure Objects</title>
<para>If you're familiar with AOP, you'd be aware there are different
types of advice available: before, after, throws and around. An around
advice is very useful, because an advisor can elect whether or not to
proceed with a method invocation, whether or not to modify the
response, and whether or not to throw an exception. Acegi Security
provides an around advice for method invocations as well as web
requests. We achieve an around advice for method invocations using AOP
Alliance, and we achieve an around advice for web requests using a
standard Filter.</para>
<para>For those not familiar with AOP, the key point to understand is
that Acegi Security can help you protect method invocations as well as
web requests. Most people are interested in securing method
invocations on their services layer. This is because the services
layer is where most business logic resides in current-generation J2EE
applications (for clarification, the author disapproves of this design
and instead advocates properly encapsulated domain objects together
with the DTO, assembly, facade and transparent persistence patterns,
but as anemic domain objects is the present mainstream approach, we'll
talk about it here). If you just need to secure method invocations to
the services layer, using the Spring's standard AOP platform
(otherwise known as AOP Alliance) will be adequate. If you need to
secure domain objects directly, you will likely find that AspectJ is
worth considering.</para>
<para>You can elect to perform method authorization using AspectJ or
AOP Alliance, or you can elect to perform web request authorization
using filters. You can use zero, one, two or three of these approaches
together. The mainstream usage is to perform some web request
authorization, coupled with some AOP Alliance method invocation
authorization on the services layer.</para>
<para>Acegi Security uses the term "secure object" to refer to any
object that can have security applies to it. Each secure object
supported by Acegi Security has its own class, which is a subclass of
<literal>AbstractSecurityInterceptor</literal>. Importantly, by the
time the <literal>AbstractSecurityInterceptor</literal> is run, the
<literal>SecurityContextHolder</literal> will contain a valid
<literal>Authentication</literal> if the principal has been
authenticated.</para>
<para>The <literal>AbstractSecurityInterceptor</literal> provides a
consistent workflow for handling secure object requests. This workflow
includes looking up the "configuration attributes" associated with the
present request. A "configuration attribute" can be thought of as a
String that has special meaning to the classes used by
<literal>AbstractSecurityInterceptor</literal>. They're normally
configured against your AbstractSecurityInterceptor using XML. Anyway,
the <literal>AbstractSecurityInterceptor</literal> will ask an
<literal>AccessDecisionManager</literal> "here's the configuration
attributes, here's the current <literal>Authentication</literal>
object, and here's details of the current request - is this particular
principal allowed to perform this particular operation?".</para>
<para>Assuming <literal>AccessDecisionManager</literal> decides to
allow the request, the <literal>AbstractSecurityInterceptor</literal>
will normally just proceed with the request. Having said that, on rare
occasions users may want to replace the
<literal>Authentication</literal> inside the
<literal>SecurityContext</literal> with a different
<literal>Authentication</literal>, which is handled by the
<literal>AccessDecisionManager</literal> calling a
<literal>RunAsManager</literal>. This might be useful in reasonably
unusual situations, such as if a services layer method needs to call a
remote system and present a different identity. Because Acegi Security
automatically propagates security identity from one server to another
(assuming you're using a properly-configured RMI or HttpInvoker
remoting protocol client), this may be useful.</para>
<para>Following the secure object proceeding and then returning -
which may mean a method invocation completing or a filter chain
proceeding - the <literal>AbstractSecurityInterceptor</literal> gets
one final chance to handle the invocation. At this stage the
<literal>AbstractSecurityInterceptor</literal> is interested in
possibly modifying the return object. We might want this to happen
because an authorization decision couldn't be made "on the way in" to
a secure object invocation. Being highly pluggable,
<literal>AbstractSecurityInterceptor</literal> will pass control to an
<literal>AfterInvocationManager</literal> to actually modify the
object if needed. This class even can entirely replace the object, or
throw an exception, or not change it in any way.</para>
<para>Because <literal>AbstractSecurityInterceptor</literal> is the
central template class, it seems fitting that the first figure should
be devoted to it.</para>
<para><mediaobject>
<imageobject role="html">
<imagedata align="center"
fileref="images/SecurityInterception.gif"
format="GIF" />
</imageobject>
<caption>
<para>Figure 1: The key "secure object" model</para>
</caption>
</mediaobject></para>
<para>Only developers contemplating an entirely new way of
intercepting and authorizing requests would need to use secure objects
directly. For example, it would be possible to build a new secure
object to secure calls to a messaging system. Anything that requires
security and also provides a way of intercepting a call (like the AOP
around advice semantics) is capable of being made into a secure
object. Having said that, most Spring applications will simply use the
three currently supported secure object types (AOP Alliance
<literal>MethodInvocation</literal>, AspectJ
<literal>JoinPoint</literal> and web request
<literal>FilterInterceptor</literal>) with complete
transparency.</para>
</sect1>
<sect1 id="common-conclusion">
<title>Conclusion</title>
<para>Congratulations! You have enough of a high-level picture of
Acegi Security to embark on your project. We've explored the shared
components, how authentication works, and reviewed the common
authorization concept of a "secure object". Everything that follows in
this reference guide may or may not apply to your particular needs,
and can be read in any order.</para>
</sect1>
</chapter>
<chapter id="supporting-infrastructure">
<title>Supporting Infrastructure</title>
<para>This chapter introduces some of the supplementary and supporting
infrastructure used by Acegi Security. If a capability is not directly
related to security, yet included in the Acegi Security project, we will
discuss it in this chapter.</para>
<sect1 id="localization">
<title>Localization</title>
<para>Acegi Security supports localization of exception messages that
end users are likely to see. If your application is designed for
English users, you don't need to do anything as by default all Acegi
Security messages are in English. If you need to support other
locales, everything you need to know is contained in this
section.</para>
<para>All exception messages can be localized, including messages
related to authentication failures and access being denied
(authorization failures). Exceptions and logging that is focused on
developers or system deployers (including incorrect attributes,
interface contract violations, using incorrect constructors, startup
time validation, debug-level logging) etc are not localized and
instead are hard-coded in English within Acegi Security's code.</para>
<para>Shipping in the <literal>acegi-security-xx.jar</literal> you
will find an <literal>org.acegisecurity</literal> package that in turn
contains a <literal>messages.properties</literal> file. This should be
referred to by your <literal>ApplicationContext</literal>, as Acegi
Security classes implement Spring's
<literal>MessageSourceAware</literal> interface and expect the message
resolver to be dependency injected at application context startup
time. Usually all you need to do is register a bean inside your
application context to refer to the messages. An example is shown
below:</para>
<para><programlisting>&lt;bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"&gt;
&lt;property name="basename"&gt;&lt;value&gt;org/acegisecurity/messages&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>The <literal>messages.properties</literal> is named in
accordance with standard resource bundles and represents the default
language supported by Acegi Securtiy messages. This default file is in
English. If you do not register a message source, Acegi Security will
still work correctly and fallback to hard-coded English versions of
the messages.</para>
<para>If you wish to customize the
<literal>messages.properties</literal> file, or support other
languages, you should copy the file, rename it accordingly, and
register it inside the above bean definition. There are not a large
number of message keys inside this file, so localization should not be
considered a major initiative. If you do perform localization of this
file, please consider sharing your work with the community by logging
a JIRA task and attaching your appropriately-named localized version
of <literal>messages.properties</literal>.</para>
<para>Rounding out the discussion on localization is the Spring
<literal>ThreadLocal</literal> known as
<literal>org.springframework.context.i18n.LocaleContextHolder</literal>.
You should set the <literal>LocaleContextHolder</literal> to represent
the preferred <literal>Locale</literal> of each user. Acegi Security
will attempt to locate a message from the message source using the
<literal>Locale</literal> obtained from this
<literal>ThreadLocal</literal>. Please refer to Spring documentation
for further details on using <literal>LocaleContextHolder</literal>
and the helper classes that can automatically set it for you (eg
<literal>AcceptHeaderLocaleResolver</literal>,
<literal>CookieLocaleResolver</literal>,
<literal>FixedLocaleResolver</literal>,
<literal>SessionLocaleResolver</literal> etc)</para>
</sect1>
<sect1 id="filters">
<title>Filters</title>
<para>Acegi Security uses many filters, as referred to throughout the
remainder of this reference guide. You have a choice in how these
filters are added to your web application, in that you can use either
<literal>FilterToBeanProxy</literal> or
<literal>FilterChainProxy</literal>. We'll look at both below.</para>
<para>Most filters are configured using the
<literal>FilterToBeanProxy</literal>. An example configuration from
<literal>web.xml</literal> follows:</para>
<para><programlisting>&lt;filter&gt;
&lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;
&lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;targetClass&lt;/param-name&gt;
&lt;param-value&gt;org.acegisecurity.ClassThatImplementsFilter&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;/filter&gt;</programlisting></para>
<para>Notice that the filter in <literal>web.xml</literal> is actually
a <literal>FilterToBeanProxy</literal>, and not the filter that will
actually implement the logic of the filter. What
<literal>FilterToBeanProxy</literal> does is delegate the
<literal>Filter</literal>'s methods through to a bean which is
obtained from the Spring application context. This enables the bean to
benefit from the Spring application context lifecycle support and
configuration flexibility. The bean must implement
<literal>javax.servlet.Filter</literal>.</para>
<para>The <literal>FilterToBeanProxy</literal> only requires a single
initialization parameter, <literal>targetClass</literal> or
<literal>targetBean</literal>. The <literal>targetClass</literal>
parameter locates the first object in the application context of the
specified class, whilst <literal>targetBean</literal> locates the
object by bean name. Like standard Spring web applications, the
<literal>FilterToBeanProxy</literal> accesses the application context
via<literal>
WebApplicationContextUtils.getWebApplicationContext(ServletContext)</literal>,
so you should configure a <literal>ContextLoaderListener</literal> in
<literal>web.xml</literal>.</para>
<para>There is a lifecycle issue to consider when hosting
<literal>Filter</literal>s in an IoC container instead of a servlet
container. Specifically, which container should be responsible for
calling the <literal>Filter</literal>'s "startup" and "shutdown"
methods? It is noted that the order of initialization and destruction
of a <literal>Filter</literal> can vary by servlet container, and this
can cause problems if one <literal>Filter</literal> depends on
configuration settings established by an earlier initialized
<literal>Filter</literal>. The Spring IoC container on the other hand
has more comprehensive lifecycle/IoC interfaces (such as
<literal>InitializingBean</literal>,
<literal>DisposableBean</literal>, <literal>BeanNameAware</literal>,
<literal>ApplicationContextAware</literal> and many others) as well as
a well-understood interface contract, predictable method invocation
ordering, autowiring support, and even options to avoid implementing
Spring interfaces (eg the <literal>destroy-method</literal> attribute
in Spring XML). For this reason we recommend the use of Spring
lifecycle services instead of servlet container lifecycle services
wherever possible. By default <literal>FilterToBeanProxy</literal>
will not delegate <literal>init(FilterConfig)</literal> and
<literal>destroy()</literal> methods through to the proxied bean. If
you do require such invocations to be delegated, set the
<literal>lifecycle</literal> initialization parameter to
<literal>servlet-container-managed</literal>.</para>
<para>Rather than using <literal>FilterToBeanProxy</literal>, we
strongly recommend to use <literal>FilterChainProxy</literal> instead.
Whilst <literal>FilterToBeanProxy</literal> is a very useful class,
the problem is that the lines of code required for
<literal>&lt;filter&gt;</literal> and
<literal>&lt;filter-mapping&gt;</literal> entries in
<literal>web.xml</literal> explodes when using more than a few
filters. To overcome this issue, Acegi Security provides a
<literal>FilterChainProxy</literal> class. It is wired using a
<literal>FilterToBeanProxy</literal> (just like in the example above),
but the target class is
<literal>org.acegisecurity.util.FilterChainProxy</literal>. The filter
chain is then declared in the application context, using code such as
this:</para>
<para><programlisting>&lt;bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"&gt;
&lt;property name="filterInvocationDefinitionSource"&gt;
&lt;value&gt;
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/webServices/**=httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
/**=httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>You may notice similarities with the way
<literal>FilterSecurityInterceptor</literal> is declared. Both regular
expressions and Ant Paths are supported, and the most specific URIs
appear first. At runtime the <literal>FilterChainProxy</literal> will
locate the first URI pattern that matches the current web request.
Each of the corresponding configuration attributes represent the name
of a bean defined in the application context. The filters will then be
invoked in the order they are specified, with standard
<literal>FilterChain</literal> behaviour being respected (a
<literal>Filter</literal> can elect not to proceed with the chain if
it wishes to end processing).</para>
<para>As you can see, <literal>FilterChainProxy</literal> requires the
duplication of filter names for different request patterns (in the
above example, <literal>exceptionTranslationFilter</literal> and
<literal>filterSecurityInterceptor</literal> are duplicated). This
design decision was made to enable <literal>FilterChainProxy</literal>
to specify different <literal>Filter</literal> invocation orders for
different URI patterns, and also to improve both the expressiveness
(in terms of regular expressions, Ant Paths, and any custom
<literal>FilterInvocationDefinitionSource</literal> implementations)
and clarity of which <literal>Filter</literal>s should be
invoked.</para>
<para>You may have noticed we have declared two
<literal>HttpSessionContextIntegrationFilter</literal>s in the filter
chain (<literal>ASC</literal> is short for
<literal>allowSessionCreation</literal>, a property of
<literal>HttpSessionContextIntegrationFilter</literal>). As web
services will never present a <literal>jsessionid</literal> on future
requests, creating <literal>HttpSession</literal>s for such user
agents would be wasteful. If you had a high-volume application which
required maximum scalability, we recommend you use the approach shown
above. For smaller applications, using a single
<literal>HttpSessionContextIntegrationFilter</literal> (with its
default <literal>allowSessionCreation</literal> as
<literal>true</literal>) would likely be sufficient.</para>
<para>In relation to lifecycle issues, the
<literal>FilterChainProxy</literal> will always delegate
<literal>init(FilterConfig)</literal> and <literal>destroy()</literal>
methods through to the underlaying <literal>Filter</literal>s if such
methods are called against <literal>FilterChainProxy</literal> itself.
In this case, <literal>FilterChainProxy</literal> guarantees to only
initialize and destroy each <literal>Filter</literal> once,
irrespective of how many times it is declared by the
<literal>FilterInvocationDefinitionSource</literal>. You control the
overall choice as to whether these methods are called or not via the
<literal>lifecycle</literal> initialization parameter of the
<literal>FilterToBeanProxy</literal> that proxies
<literal>FilterChainProxy</literal>. As discussed above, by default
any servlet container lifecycle invocations are not delegated through
to <literal>FilterChainProxy</literal>.</para>
<para>The order that filters are defined in <literal>web.xml</literal>
is very important. Irrespective of which filters you are actually
using, the order of the <literal>&lt;filter-mapping&gt;</literal>s
should be as follows:</para>
<orderedlist>
<listitem>
<para><literal>ChannelProcessingFilter</literal>, because it might
need to redirect to a different protocol</para>
</listitem>
<listitem>
<para><literal>ConcurrentSessionFilter</literal>, because it
doesn't use any <literal>SecurityContextHolder</literal>
functionality but needs to update the
<literal>SessionRegistry</literal> to reflect ongoing requests
from the principal</para>
</listitem>
<listitem>
<para><literal>HttpSessionContextIntegrationFilter</literal>, so a
<literal>SecurityContext</literal> can be setup in the
<literal>SecurityContextHolder</literal> at the beginning of a web
request, and any changes to the <literal>SecurityContext</literal>
can be copied to the <literal>HttpSession</literal> when the web
request ends (ready for use with the next web request)</para>
</listitem>
<listitem>
<para>Authentication processing mechanisms -
<literal>AuthenticationProcessingFilter</literal>,
<literal>CasProcessingFilter</literal>,
<literal>BasicProcessingFilter, HttpRequestIntegrationFilter,
JbossIntegrationFilter</literal> etc - so that the
<literal>SecurityContextHolder</literal> can be modified to
contain a valid <literal>Authentication</literal> request
token</para>
</listitem>
<listitem>
<para>The
<literal>SecurityContextHolderAwareRequestFilter</literal>, if you
are using it to install an Acegi Security aware
<literal>HttpServletRequestWrapper</literal> into your servlet
container</para>
</listitem>
<listitem>
<para><literal>RememberMeProcessingFilter</literal>, so that if no
earlier authentication processing mechanism updated the
<literal>SecurityContextHolder</literal>, and the request presents
a cookie that enables remember-me services to take place, a
suitable remembered
<literal><literal>Authentication</literal></literal> object will
be put there</para>
</listitem>
<listitem>
<para><literal>AnonymousProcessingFilter</literal>, so that if no
earlier authentication processing mechanism updated the
<literal>SecurityContextHolder</literal>, an anonymous
<literal>Authentication</literal> object will be put there</para>
</listitem>
<listitem>
<para><literal>ExceptionTranslationFilter</literal>, to catch any
Acegi Security exceptions so that either a HTTP error response can
be returned or an appropriate
<literal>AuthenticationEntryPoint</literal> can be launched</para>
</listitem>
<listitem>
<para><literal>FilterSecurityInterceptor</literal>, to protect web
URIs</para>
</listitem>
</orderedlist>
<para>All of the above filters use
<literal>FilterToBeanProxy</literal> or
<literal>FilterChainProxy</literal>. It is recommended that a single
<literal>FilterToBeanProxy</literal> proxy through to a single
<literal>FilterChainProxy</literal> for each application, with that
<literal>FilterChainProxy</literal> defining all of Acegi Security
<literal>Filter</literal>s.</para>
<para>If you're using SiteMesh, ensure Acegi Security filters execute
before the SiteMesh filters are called. This enables the
<literal>SecurityContextHolder</literal> to be populated in time for
use by SiteMesh decorators</para>
</sect1>
</chapter>
<chapter id="channel-security">
<title>Channel Security</title>
<sect1 id="channel-security-overview">
<title>Overview</title>
<para>In addition to coordinating the authentication and authorization
requirements of your application, Acegi Security is also able to
ensure unauthenticated web requests have certain properties. These
properties may include being of a particular transport type, having a
particular <literal>HttpSession</literal> attribute set and so on. The
most common requirement is for your web requests to be received using
a particular transport protocol, such as HTTPS.</para>
<para>An important issue in considering transport security is that of
session hijacking. Your web container manages a
<literal>HttpSession</literal> by reference to a
<literal>jsessionid</literal> that is sent to user agents either via a
cookie or URL rewriting. If the <literal>jsessionid</literal> is ever
sent over HTTP, there is a possibility that session identifier can be
intercepted and used to impersonate the user after they complete the
authentication process. This is because most web containers maintain
the same session identifier for a given user, even after they switch
from HTTP to HTTPS pages.</para>
<para>If session hijacking is considered too significant a risk for
your particular application, the only option is to use HTTPS for every
request. This means the <literal>jsessionid</literal> is never sent
across an insecure channel. You will need to ensure your
<literal>web.xml</literal>-defined
<literal>&lt;welcome-file&gt;</literal> points to a HTTPS location,
and the application never directs the user to a HTTP location. Acegi
Security provides a solution to assist with the latter.</para>
</sect1>
<sect1 id="channel-security-config">
<title>Configuration</title>
<para>To utilise Acegi Security's channel security services, add the
following lines to <literal>web.xml</literal>:</para>
<para><programlisting>
&lt;filter&gt;
&lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;
&lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;targetClass&lt;/param-name&gt;
&lt;param-value&gt;org.acegisecurity.securechannel.ChannelProcessingFilter&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;Acegi Channel Processing Filter&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;
</programlisting></para>
<para>As usual when running <literal>FilterToBeanProxy</literal>, you
will also need to configure the filter in your application
context:</para>
<para><programlisting>
&lt;bean id="channelProcessingFilter" class="org.acegisecurity.securechannel.ChannelProcessingFilter"&gt;
&lt;property name="channelDecisionManager"&gt;&lt;ref bean="channelDecisionManager"/&gt;&lt;/property&gt;
&lt;property name="filterInvocationDefinitionSource"&gt;
&lt;value&gt;
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/secure/.*\Z=REQUIRES_SECURE_CHANNEL
\A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL
\A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL
\A.*\Z=REQUIRES_INSECURE_CHANNEL
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="channelDecisionManager" class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl"&gt;
&lt;property name="channelProcessors"&gt;
&lt;list&gt;
&lt;ref bean="secureChannelProcessor"/&gt;
&lt;ref bean="insecureChannelProcessor"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="secureChannelProcessor" class="org.acegisecurity.securechannel.SecureChannelProcessor"/&gt;
&lt;bean id="insecureChannelProcessor" class="org.acegisecurity.securechannel.InsecureChannelProcessor"/&gt;
</programlisting></para>
<para>Like <literal>FilterSecurityInterceptor</literal>, Apache Ant
style paths are also supported by the
<literal>ChannelProcessingFilter</literal>.</para>
<para>The <literal>ChannelProcessingFilter</literal> operates by
filtering all web requests and determining the configuration
attributes that apply. It then delegates to the
<literal>ChannelDecisionManager</literal>. The default implementation,
<literal>ChannelDecisionManagerImpl</literal>, should suffice in most
cases. It simply delegates through the list of configured
<literal>ChannelProcessor</literal> instances. A
<literal>ChannelProcessor</literal> will review the request, and if it
is unhappy with the request (eg it was received across the incorrect
transport protocol), it will perform a redirect, throw an exception or
take whatever other action is appropriate.</para>
<para>Included with Acegi Security are two concrete
<literal>ChannelProcessor</literal> implementations:
<literal>SecureChannelProcessor</literal> ensures requests with a
configuration attribute of <literal>REQUIRES_SECURE_CHANNEL</literal>
are received over HTTPS, whilst
<literal>InsecureChannelProcessor</literal> ensures requests with a
configuration attribute of
<literal>REQUIRES_INSECURE_CHANNEL</literal> are received over HTTP.
Both implementations delegate to a
<literal>ChannelEntryPoint</literal> if the required transport
protocol is not used. The two <literal>ChannelEntryPoint</literal>
implementations included with Acegi Security simply redirect the
request to HTTP and HTTPS as appropriate. Appropriate defaults are
assigned to the <literal>ChannelProcessor</literal> implementations
for the configuration attribute keywords they respond to and the
<literal>ChannelEntryPoint</literal> they delegate to, although you
have the ability to override these using the application
context.</para>
<para>Note that the redirections are absolute (eg
<literal>http://www.company.com:8080/app/page</literal>), not relative
(eg <literal>/app/page</literal>). During testing it was discovered
that Internet Explorer 6 Service Pack 1 has a bug whereby it does not
respond correctly to a redirection instruction which also changes the
port to use. Accordingly, absolute URLs are used in conjunction with
bug detection logic in the <literal>PortResolverImpl</literal> that is
wired up by default to many Acegi Security beans. Please refer to the
JavaDocs for <literal>PortResolverImpl</literal> for further
details.</para>
<para>You should note that using a secure channel is recommended if
usernames and passwords are to be kept secure during the login
process. If you do decide to use
<literal>ChannelProcessingFilter</literal> with form-based login,
please ensure that your login page is set to
<literal>REQUIRES_SECURE_CHANNEL</literal>, and that the
<literal>AuthenticationProcessingFilterEntryPoint.forceHttps</literal>
property is <literal>true</literal>.</para>
</sect1>
<sect1 id="channel-security-conclusion">
<title>Conclusion</title>
<para>Once configured, using the channel security filter is very easy.
Simply request pages without regard to the protocol (ie HTTP or HTTPS)
or port (eg 80, 8080, 443, 8443 etc). Obviously you'll still need a
way of making the initial request (probably via the
<literal>web.xml</literal> <literal>&lt;welcome-file&gt;</literal> or
a well-known home page URL), but once this is done the filter will
perform redirects as defined by your application context.</para>
<para>You can also add your own <literal>ChannelProcessor</literal>
implementations to the <literal>ChannelDecisionManagerImpl</literal>.
For example, you might set a <literal>HttpSession</literal> attribute
when a human user is detected via a "enter the contents of this
graphic" procedure. Your <literal>ChannelProcessor</literal> would
respond to say <literal>REQUIRES_HUMAN_USER</literal> configuration
attributes and redirect to an appropriate entry point to start the
human user validation process if the <literal>HttpSession</literal>
attribute is not currently set.</para>
<para>To decide whether a security check belongs in a
<literal>ChannelProcessor</literal> or an
<literal>AccessDecisionVoter</literal>, remember that the former is
designed to handle unauthenticated requests, whilst the latter is
designed to handle authenticated requests. The latter therefore has
access to the granted authorities of the authenticated principal. In
addition, problems detected by a <literal>ChannelProcessor</literal>
will generally cause a HTTP/HTTPS redirection so its requirements can
be met, whilst problems detected by an
<literal>AccessDecisionVoter</literal> will ultimately result in an
<literal>AccessDeniedException</literal> (depending on the governing
<literal>AccessDecisionManager</literal>).</para>
</sect1>
</chapter>
<chapter id="taglib">
<title>Tag Libraries</title>
<sect1 id="taglib-overview">
<title>Overview</title>
<para>Acegi Security comes bundled with several JSP tag libraries that
eases JSP writing. The tag libraries are known as
<literal>authz</literal> and provide a range of different
services.</para>
</sect1>
<sect1 id="taglib-config">
<title>Configuration</title>
<para>All taglib classes are included in the core
<literal>acegi-security-xx.jar</literal> file, with the
<literal>authz.tld</literal> located in the JAR's
<literal>META-INF</literal> directory. This means for JSP 1.2+ web
containers you can simply include the JAR in the WAR's
<literal>WEB-INF/lib</literal> directory and it will be available. If
you're using a JSP 1.1 container, you'll need to declare the JSP
taglib in your <literal>web.xml file</literal>, and include
<literal>authz.tld</literal> in the <literal>WEB-INF/lib</literal>
directory. The following fragment is added to
<literal>web.xml</literal>:</para>
<para><programlisting>&lt;taglib&gt;
&lt;taglib-uri&gt;http://acegisecurity.org/authz&lt;/taglib-uri&gt;
&lt;taglib-location&gt;/WEB-INF/authz.tld&lt;/taglib-location&gt;
&lt;/taglib&gt; </programlisting></para>
</sect1>
<sect1 id="taglib-usage">
<title>Usage</title>
<para>Now that you've configured the tag libraries, refer to the
individual reference guide sections for details on how to use
them.</para>
</sect1>
</chapter>
</part>
<part id="authentication">
<title>Authentication</title>
<partintro>
<para>In this part of the reference guide we will examine individual
authentication mechanisms and their corresponding
<literal>AuthenticationProvider</literal>s. We'll also look at how to
configure authentication more generally, including if you have several
authentication approaches that need to be chained together.</para>
</partintro>
<chapter id="authentication-common-auth-services">
<title>Common Authentication Services</title>
<sect1 id="mechanisms-providers-entry-points">
<title>Mechanisms, Providers and Entry Points</title>
<para>If you're using Acegi Security-provided authentication
approaches, you'll usually need to configure a web filter, together
with an <literal>AuthenticationProvider</literal> and
<literal>AuthenticationEntryPoint</literal>. In this section we are
going to explore an example application that needs to support both
form-based authentication (ie so a nice HTML page is presented to a
user for them to login) plus BASIC authentication (ie so a web service
or similar can access protected resources).</para>
<para>In the web.xml, this application will need a single Acegi
Security filter in order to use the FilterChainProxy. Nearly every
Acegi Security application will have such an entry, and it looks like
this:</para>
<para><programlisting>&lt;filter&gt;
&lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;
&lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;targetClass&lt;/param-name&gt;
&lt;param-value&gt;org.acegisecurity.util.FilterChainProxy&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;</programlisting></para>
<para>The above declarations will cause every web request to be passed
through to Acegi Security's FilterChainProxy. As explained in the
filters section of this reference guide, the FilterChainProxy is a
generally-useful class that enables web requests to be passed to
different filters based on the URL patterns. Those delegated filters
are managed inside the application context, so they can benefit from
dependency injection. Let's have a look at what the FilterChainProxy
bean definition would look like inside your application
context:</para>
<para><programlisting>&lt;bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"&gt;
&lt;property name="filterInvocationDefinitionSource"&gt;
&lt;value&gt;
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,switchUserProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;</programlisting></para>
<para>Internally Acegi Security will use a
<literal>PropertyEditor</literal> to convert the string presented in
the above XML fragment into a
<literal>FilterInvocationDefinitionSource</literal> object. What's
important to note at this stage is that a series of filters will be
run - in the order specified by the declaration - and each of those
filters are actually the <literal>&lt;bean id&gt;</literal> of another
bean inside the application context. So, in our case some extra beans
will also appear in the application context, and they'll be named
<literal>httpSessionContextIntegrationFilter</literal>,
<literal>logoutFilter</literal> and so on. The order that the filters
should appear is discussed in the filters section of the reference
guide - although they are correct in the above example.</para>
<para>In our example we have the
<literal>AuthenticationProcessingFilter</literal> and
<literal>BasicProcessingFilter</literal> being used. These are the
"authentication mechanisms" that respond to form-based authentication
and BASIC HTTP header-based authentication respectively (we discussed
the role of authentication mechanisms earlier in this reference
guide). If you weren't using form or BASIC authentication, neither of
these beans would be defined. You'd instead define filters applicable
to your desired authentication environment, such as
<literal>DigestProcessingFilter</literal> or
<literal>CasProcessingFilter</literal>. Refer to the individual
chapters of this part of the reference guide to learn how to configure
each of these authentication mechanisms.</para>
<para>Recall that
<literal>HttpSessionContextIntegrationFilter</literal> keeps the
contents of the <literal>SecurityContext</literal> between invocations
inside a HTTP session. This means the authentication mechanisms are
only used once, being when the principal initially tries to
authenticate. The rest of the time the authentication mechanisms sit
there and silently pass the request through to the next filter in the
chain. That is a practical requirement due to the fact that few
authentication approaches present credentials on each and every call
(BASIC authentication being a notable exception), but what happens if
a principal's account gets cancelled or disabled or otherwise changed
(eg an increase or decrease in <literal>GrantedAuthority[]</literal>s)
after the initial authentication step? Let's look at how that is
handled now.</para>
<para>The major authorization provider for secure objects has
previously been introduced as
<literal>AbstractSecurityInterceptor</literal>. This class needs to
have access to an <literal>AuthenticationManager</literal>. It also
has configurable settings to indicate whether an
<literal>Authentication</literal> object should be re-authenticated on
each secure object invocation. By default it just accepts any
<literal>Authentication</literal> inside the
<literal>SecurityContextHolder</literal> is authenticated if
<literal>Authentication.isAuthenticated()</literal> returns true. This
is great for performance, but not ideal if you want to ensure
up-to-the-moment authentication validity. For such cases you'll
probably want to set the
<literal>AbstractSecurityInterceptor.alwaysReauthenticate</literal>
property to true.</para>
<para>You might be asking yourself, "what's this
<literal>AuthenticationManager</literal>?". We haven't explored it
before, but we have discussed the concept of an
<literal>AuthenticationProvider</literal>. Quite simply, an
AuthenticationManager is responsible for passing requests through a
chain of AuthenticationProviders. It's a little like the filter chain
we discussed earlier, although there are some differences. There is
only one AuthenticationManager implementation shipped with Acegi
Security, so let's look at how it's configured for the example we're
using in this chapter:</para>
<para><programlisting>&lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt;
&lt;property name="providers"&gt;
&lt;list&gt;
&lt;ref local="daoAuthenticationProvider"/&gt;
&lt;ref local="anonymousAuthenticationProvider"/&gt;
&lt;ref local="rememberMeAuthenticationProvider"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;</programlisting></para>
<para>It's probably worth mentioning at this point that your
authentication mechanisms (which are usually filters) are also
injected with a reference to the
<literal>AuthenticationManager</literal>. So both
<literal>AbstractSecurityInterceptor</literal> as well as the
authentication mechanisms will use the above
<literal>ProviderManager</literal> to poll a list of
<literal>AuthenticationProvider</literal>s.</para>
<para>In our example we have three providers. They are tried in the
order shown (which is implied by the use of a <literal>List</literal>
instead of a <literal>Set</literal>), with each provider able to
attempt authentication, or skip authentication by simply returning
<literal>null</literal>. If all implementations return null, the
<literal>ProviderManager</literal> will throw a suitable exception. If
you're interested in learning more about chaining providers, please
refer to the <literal>ProviderManager</literal> JavaDocs.</para>
<para>The providers to use will sometimes be interchangeable with the
authentication mechanisms, whilst at other times they will depend on a
specific authentication mechanism. For example, the
<literal>DaoAuthenticationProvider</literal> just needs a string-based
username and password. Various authentication mechanisms result in the
collection of a string-based username and password, including (but not
limited to) BASIC and form authentication. Equally, some
authentication mechanisms create an authentication request object
which can only be interpreted by a single type of
<literal>AuthenticationProvider</literal>. An example of this
one-to-one mapping would be JA-SIG CAS, which uses the notion of a
service ticket which can therefore only be authenticated by
<literal>CasAuthenticationProvider</literal>. A further example of a
one-to-one mapping would be the LDAP authentication mechanism, which
can only be processed an the
<literal>LdapAuthenticationProvider</literal>. The specifics of such
relationships are detailed in the JavaDocs for each class, plus the
authentication approach-specific chapters of this reference guide. You
need not be terribly concerned about this implementation detail,
because if you forget to register a suitable provider, you'll simply
receive a <literal>ProviderNotFoundException</literal> when an attempt
to authenticate is made.</para>
<para>After configuring the correct authentication mechanisms in the
<literal>FilterChainProxy</literal>, and ensuring that a corresponding
<literal>AuthenticationProvider</literal> is registered in the
<literal>ProviderManager</literal>, your last step is to configure an
<literal>AuthenticationEntryPoint</literal>. Recall that earlier we
discussed the role of <literal>ExceptionTranslationFilter</literal>,
which is used when HTTP-based requests should receive back a HTTP
header or HTTP redirect in order to start authentication. Continuing
on with our earlier example:</para>
<para><programlisting>&lt;bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"&gt;
&lt;property name="authenticationEntryPoint"&gt;&lt;ref local="authenticationProcessingFilterEntryPoint"/&gt;&lt;/property&gt;
&lt;property name="accessDeniedHandler"&gt;
&lt;bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"&gt;
&lt;property name="errorPage" value="/accessDenied.jsp"/&gt;
&lt;/bean&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"&gt;
&lt;property name="loginFormUrl"&gt;&lt;value&gt;/acegilogin.jsp&lt;/value&gt;&lt;/property&gt;
&lt;property name="forceHttps"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;</programlisting></para>
<para>Notice that the <literal>ExceptionTranslationFilter</literal>
requires two collaborators. The first,
<literal>AccessDeniedHandlerImpl</literal>, uses a
<literal>RequestDispatcher</literal> forward to display the specified
access denied error page. We use a forward so that the
<literal>SecurityContextHolder</literal> still contains details of the
principal, which may be useful for display to the user (in old
releases of Acegi Security we relied upon the servlet container to
handle a 403 error message, which lacked this useful contextual
information). <literal>AccessDeniedHandlerImpl</literal> will also set
the HTTP header to 403, which is the official error code to indicate
access denied. In the case of the
<literal>AuthentionEntryPoint</literal>, here we're setting what
action we would like taken when an unauthenticated principal attempts
to perform a protected operation. Because in our example we're going
to be using form-based authentication, we specify
<literal>AuthenticationProcessinFilterEntryPoint</literal> and the URL
of the login page. Your application will usually only have one entry
point, and most authentication approaches define their own specific
<literal>AuthenticationEntryPoint</literal>. Details of which entry
point to use for each authentication approach is discussed in the
authentication approach-specific chapters of this reference
guide.</para>
</sect1>
<sect1 id="userdetails-and-associated-types">
<title>UserDetails and Associated Types</title>
<para>As mentioned in the first part of the reference guide, most
authentication providers take advantage of the
<literal>UserDetails</literal> and
<literal>UserDetailsService</literal> interfaces. The contract for
this latter interface consists of a single method:</para>
<para><programlisting>public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;</programlisting></para>
<para>The returned <literal>UserDetails</literal> is an interface that
provides getters that guarantee non-null provision of basic
authentication information such as the username, password, granted
authorities and whether the user is enabled or disabled. Most
authentication providers will use a
<literal>UserDetailsService</literal>, even if the username and
password are not actually used as part of the authentication decision.
Generally such provider will be using the returned
<literal>UserDetails</literal> object just for its
<literal>GrantedAuthority[]</literal> information, because some other
system (like LDAP or X509 or CAS etc) has undertaken the
responsibility of actually validating the credentials.</para>
<para>A single concrete implementation of
<literal>UserDetails</literal> is provided with Acegi Security, being
the <literal>User</literal> class. Acegi Security users will need to
decide when writing their <literal>UserDetailsService</literal> what
concrete <literal>UserDetails</literal> class to return. In most cases
<literal>User</literal> will be used directly or subclassed, although
special circumstances (such as object relational mappers) may require
users to write their own <literal>UserDetails</literal> implementation
from scratch. This is not such an unusual situation, and users should
not hesitate to simply return their normal domain object that
represents a user of the system. This is especially common given that
<literal>UserDetails</literal> is often used to store additional
principal-related properties (such as their telephone number and email
address), so that they can be easily used by web views.</para>
<para>Given <literal>UserDetailsService</literal> is so simple to
implement, it should be easy for users to retrieve authentication
information using a persistence strategy of their choice. Having said
that, Acegi Security does include a couple of useful base
implementations, which we'll look at below.</para>
<sect2 id="in-memory-service">
<title>In-Memory Authentication</title>
<para>Whilst it is easy to use create a custom
<literal>UserDetailsService</literal> implementation that extracts
information from a persistence engine of choice, many applications
do not require such complexity. This is particularly true if you're
undertaking a rapid prototype or just starting integrating Acegi
Security, when you don't really want to spend time configuring
databases or writing <literal>UserDetailsService</literal>
implementations. For this sort of situation, a simple option is to
configure the <literal>InMemoryDaoImpl</literal>
implementation:</para>
<para><programlisting>&lt;bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"&gt;
&lt;property name="userMap"&gt;
&lt;value&gt;
marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
dianne=emu,ROLE_TELLER
scott=wombat,ROLE_TELLER
peter=opal,disabled,ROLE_TELLER
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>In the above example, the <literal>userMap</literal> property
contains each of the usernames, passwords, a list of granted
authorities and an optional enabled/disabled keyword. Commas are
used to delimit each token. The username must appear to the left of
the equals sign, and the password must be the first token to the
right of the equals sign. The <literal>enabled</literal> and
<literal>disabled</literal> keywords (case insensitive) may appear
in the second or any subsequent token. Any remaining tokens are
treated as granted authorities, which are created as
<literal>GrantedAuthorityImpl</literal> objects (this is just for
your reference - most application don't need custom
<literal>GrantedAuthority</literal> implementations, so using the
default implementation in this manner is just fine). Note that if a
user has no password and/or no granted authorities, the user will
not be created in the in-memory authentication repository.</para>
<para><literal>InMemoryDaoImpl</literal> also offers a
<literal>setUserProperties(Properties)</literal> method, which
allows you to externalise the
<literal>java.util.Properties</literal> in another Spring configured
bean or an external properties file. You might like to use Spring's
<literal>PropertiesFactoryBean</literal>, which is useful for
loading such external properties files. This setter might prove
useful for simple applications that have a larger number of users,
or deployment-time configuration changes, but do not wish to use a
full database for handling authentication details.</para>
</sect2>
<sect2 id="jdbc-service">
<title>JDBC Authentication</title>
<para>Acegi Security also includes a
<literal>UserDetailsService</literal> that can obtain authentication
information from a JDBC data source. Internally Spring JDBC is used,
so it avoids the complexity of a fully-featured object relational
mapper (ORM) just to store user details. If your application does
use an ORM tool, you might prefer to write a custom
<literal>UserDetailsService</literal> to reuse the mapping files
you've probably already created. Returning to
<literal>JdbcDaoImpl</literal>, an example configuration is shown
below:</para>
<para><programlisting>&lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;
&lt;property name="driverClassName"&gt;&lt;value&gt;org.hsqldb.jdbcDriver&lt;/value&gt;&lt;/property&gt;
&lt;property name="url"&gt;&lt;value&gt;jdbc:hsqldb:hsql://localhost:9001&lt;/value&gt;&lt;/property&gt;
&lt;property name="username"&gt;&lt;value&gt;sa&lt;/value&gt;&lt;/property&gt;
&lt;property name="password"&gt;&lt;value&gt;&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl"&gt;
&lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>You can use different relational database management systems
by modifying the <literal>DriverManagerDataSource</literal> shown
above. You can also use a global data source obtained from JNDI, as
per normal Spring options. Irrespective of the database used and how
a <literal>DataSource</literal> is obtained, a standard schema must
be used as indicated in <literal>dbinit.txt</literal>. You can
download this file from the Acegi Security web site.</para>
<para>If you default schema is unsuitable for your needs,
<literal>JdbcDaoImpl</literal> provides two properties that allow
customisation of the SQL statements. You may also subclass the
<literal>JdbcDaoImpl</literal> if further customisation is
necessary. Please refer to the JavaDocs for details, although please
note that the class is not intended for complex custom subclasses.
If you have complex needs (such as a special schema or would like a
certain <literal>UserDetails</literal> implementation returned),
you'd be better off writing your own
<literal>UserDetailsService</literal>. The base implementation
provided with Acegi Security is intended for typical situations, and
does not offer infinite configuration flexibility.</para>
</sect2>
</sect1>
<sect1 id="concurrent-sessions">
<title>Concurrent Session Handling</title>
<para>Acegi Security is able to prevent a principal from concurrently
authenticating to the same application more than a specified number of
times. Many ISVs take advantage of this to enforce licensing, whilst
network administrators like this feature because it helps prevent
people from sharing login names. You can, for example, stop user
"Batman" from logging onto the web application from two different
sessions.</para>
<para>To use concurrent session support, you'll need to add the
following to <literal>web.xml</literal>:</para>
<para><programlisting>&lt;listener&gt;
&lt;listener-class&gt;org.acegisecurity.ui.session.HttpSessionEventPublisher&lt;/listener-class&gt;
&lt;/listener&gt; </programlisting></para>
<para>In addition, you will need to add the
<literal>org.acegisecurity.concurrent.ConcurrentSessionFilter</literal>
to your <literal>FilterChainProxy</literal>. The
ConcurrentSessionFilter requires two properties,
<literal>sessionRegistry</literal>, which generally points to an
instance of <literal>SessionRegistryImpl</literal>, and
<literal>expiredUrl</literal>, which points to the page to display
when a session has expired.</para>
<para>The <literal>web.xml</literal>
<literal>HttpSessionEventPublisher</literal> causes an
<literal>ApplicationEvent</literal> to be published to the Spring
<literal>ApplicationContext</literal> every time a
<literal>HttpSession</literal> commences or terminates. This is
critical, as it allows the <literal>SessionRegistryImpl</literal> to
be notified when a session ends.</para>
<para>You will also need to wire up the
<literal>ConcurrentSessionControllerImpl</literal> and refer to it
from your <literal>ProviderManager</literal> bean:</para>
<para><programlisting>&lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt;
&lt;property name="providers"&gt;
&lt;!-- your providers go here --&gt;
&lt;/property&gt;
&lt;property name="sessionController"&gt;&lt;ref bean="concurrentSessionController"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="concurrentSessionController" class="org.acegisecurity.concurrent.ConcurrentSessionControllerImpl"&gt;
&lt;property name="maximumSessions"&gt;&lt;value&gt;1&lt;/value&gt;&lt;/property&gt;
&lt;property name="sessionRegistry"&gt;&lt;ref local="sessionRegistry"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="sessionRegistry" class="org.acegisecurity.concurrent.SessionRegistryImpl"/&gt;</programlisting></para>
</sect1>
<sect1 id="authentication-taglibs">
<title>Authentication Tag Libraries</title>
<para><literal>AuthenticationTag</literal> is used to simply output a
property of the current principal's
<literal>Authentication.getPrincipal()</literal> object to the web
page.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AuthenticationTag</literal>:</para>
<para><programlisting>&lt;authz:authentication operation="username"/&gt;</programlisting></para>
<para>This tag would cause the principal's name to be output. Here we
are assuming the <literal>Authentication.getPrincipal()</literal> is a
<literal>UserDetails</literal> object, which is generally the case
when using the typical
<literal>DaoAuthenticationProvider</literal>.</para>
</sect1>
</chapter>
<chapter id="dao-provider">
<title>DAO Authentication Provider</title>
<sect1 id="dao-provider-overview">
<title>Overview</title>
<para>Acegi Security includes a production-quality
<literal>AuthenticationProvider</literal> implementation called
<literal>DaoAuthenticationProvider</literal>. This authentication
provider is compatible with all of the authentication mechanisms that
generate a <literal>UsernamePasswordAuthenticationToken</literal>, and
is probably the most commonly used provider in the framework. Like
most of the other authentication providers, the
DaoAuthenticationProvider leverages a UserDetailsService in order to
lookup the username, password and GrantedAuthority[]s. Unlike most of
the other authentication providers that leverage UserDetailsService,
this authentication provider actually requires the password to be
presented, and the provider will actually evaluate the validity or
otherwise of the password presented in an authentication request
object.</para>
</sect1>
<sect1 id="dao-provider-config">
<title>Configuration</title>
<para>Aside from adding DaoAuthenticationProvider to your
ProviderManager list (as discussed at the start of this part of the
reference guide), and ensuring a suitable authentication mechanism is
configured to present a UsernamePasswordAuthenticationToken, the
configuration of the provider itself is rather simple:</para>
<para><programlisting>&lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;
&lt;property name="userDetailsService"&gt;&lt;ref bean="inMemoryDaoImpl"/&gt;&lt;/property&gt;
&lt;property name="saltSource"&gt;&lt;ref bean="saltSource"/&gt;&lt;/property&gt;
&lt;property name="passwordEncoder"&gt;&lt;ref bean="passwordEncoder"/&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>The <literal>PasswordEncoder</literal> and
<literal>SaltSource</literal> are optional. A
<literal>PasswordEncoder</literal> provides encoding and decoding of
passwords presented in the <literal>UserDetails</literal> object that
is returned from the configured <literal>UserDetailsService</literal>.
A <literal>SaltSource</literal> enables the passwords to be populated
with a "salt", which enhances the security of the passwords in the
authentication repository. <literal>PasswordEncoder</literal>
implementations are provided with Acegi Security covering MD5, SHA and
cleartext encodings. Two <literal>SaltSource</literal> implementations
are also provided: <literal>SystemWideSaltSource</literal> which
encodes all passwords with the same salt, and
<literal>ReflectionSaltSource</literal>, which inspects a given
property of the returned <literal>UserDetails</literal> object to
obtain the salt. Please refer to the JavaDocs for further details on
these optional features.</para>
<para>In addition to the properties above, the
<literal>DaoAuthenticationProvider</literal> supports optional caching
of <literal>UserDetails</literal> objects. The
<literal>UserCache</literal> interface enables the
<literal>DaoAuthenticationProvider</literal> to place a
<literal>UserDetails</literal> object into the cache, and retrieve it
from the cache upon subsequent authentication attempts for the same
username. By default the <literal>DaoAuthenticationProvider</literal>
uses the <literal>NullUserCache</literal>, which performs no caching.
A usable caching implementation is also provided,
<literal>EhCacheBasedUserCache</literal>, which is configured as
follows:</para>
<para><programlisting>&lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;
&lt;property name="userDetailsService"&gt;&lt;ref bean="userDetailsService"/&gt;&lt;/property&gt;
&lt;property name="userCache"&gt;&lt;ref bean="userCache"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&gt;
&lt;property name="configLocation"&gt;
&lt;value&gt;classpath:/ehcache-failsafe.xml&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;
&lt;property name="cacheManager"&gt;
&lt;ref local="cacheManager"/&gt;
&lt;/property&gt;
&lt;property name="cacheName"&gt;
&lt;value&gt;userCache&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"&gt;
&lt;property name="cache"&gt;&lt;ref local="userCacheBackend"/&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>All Acegi Security EH-CACHE implementations (including
<literal>EhCacheBasedUserCache</literal>) require an EH-CACHE
<literal>Cache</literal> object. The <literal>Cache</literal> object
can be obtained from wherever you like, although we recommend you use
Spring's factory classes as shown in the above configuration. If using
Spring's factory classes, please refer to the Spring documentation for
further details on how to optimise the cache storage location, memory
usage, eviction policies, timeouts etc.</para>
<para>A design decision was made not to support account locking in the
<literal>DaoAuthenticationProvider</literal>, as doing so would have
increased the complexity of the <literal>UserDetailsService</literal>
interface. For instance, a method would be required to increase the
count of unsuccessful authentication attempts. Such functionality
could be easily provided by leveraging the application event
publishing features discussed below.</para>
<para><literal>DaoAuthenticationProvider</literal> returns an
<literal>Authentication</literal> object which in turn has its
<literal>principal</literal> property set. The principal will be
either a <literal>String</literal> (which is essentially the username)
or a <literal>UserDetails</literal> object (which was looked up from
the <literal>UserDetailsService</literal>). By default the
<literal>UserDetails</literal> is returned, as this enables
applications to add extra properties potentially of use in
applications, such as the user's full name, email address etc. If
using container adapters, or if your applications were written to
operate with <literal>String</literal>s (as was the case for releases
prior to Acegi Security 0.6), you should set the
<literal>DaoAuthenticationProvider.forcePrincipalAsString</literal>
property to <literal>true</literal> in your application context</para>
</sect1>
</chapter>
<chapter id="jaas">
<title>Java Authentication and Authorization Service (JAAS)
Provider</title>
<sect1 id="jaas-overview">
<title>Overview</title>
<para>Acegi Security provides a package able to delegate
authentication requests to the Java Authentication and Authorization
Service (JAAS). This package is discussed in detail below.</para>
<para>Central to JAAS operation are login configuration files. To
learn more about JAAS login configuration files, consult the JAAS
reference documentation available from Sun Microsystems. We expect you
to have a basic understanding of JAAS and its login configuration file
syntax in order to understand this section.</para>
</sect1>
<sect1 id="jaas-config">
<title>Configuration</title>
<para>The <literal>JaasAuthenticationProvider</literal> attempts to
authenticate a users principal and credentials through JAAS.</para>
<para>Lets assume we have a JAAS login configuration file,
<literal>/WEB-INF/login.conf</literal>, with the following
contents:</para>
<para><programlisting>JAASTest {
sample.SampleLoginModule required;
};</programlisting></para>
<para>Like all Acegi Security beans, the
<literal>JaasAuthenticationProvider</literal> is configured via the
application context. The following definitions would correspond to the
above JAAS login configuration file:</para>
<para><programlisting>
&lt;bean id="jaasAuthenticationProvider" class="org.acegisecurity.providers.jaas.JaasAuthenticationProvider"&gt;
&lt;property name="loginConfig"&gt;
&lt;value&gt;/WEB-INF/login.conf&lt;/value&gt;
&lt;/property&gt;
&lt;property name="loginContextName"&gt;
&lt;value&gt;JAASTest&lt;/value&gt;
&lt;/property&gt;
&lt;property name="callbackHandlers"&gt;
&lt;list&gt;
&lt;bean class="org.acegisecurity.providers.jaas.JaasNameCallbackHandler"/&gt;
&lt;bean class="org.acegisecurity.providers.jaas.JaasPasswordCallbackHandler"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="authorityGranters"&gt;
&lt;list&gt;
&lt;bean class="org.acegisecurity.providers.jaas.TestAuthorityGranter"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
</programlisting></para>
<para>The <literal>CallbackHandler</literal>s and
<literal>AuthorityGranter</literal>s are discussed below.</para>
<sect2 id="jaas-callbackhandler">
<title id="jaas-callback-handler">JAAS CallbackHandler</title>
<para>Most JAAS <literal>LoginModule</literal>s require a callback
of some sort. These callbacks are usually used to obtain the
username and password from the user.</para>
<para>In an Acegi Security deployment, Acegi Security is responsible
for this user interaction (via the authentication mechanism). Thus,
by the time the authentication request is delegated through to JAAS,
Acegi Security's authentication mechanism will already have
fully-populated an <literal>Authentication</literal> object
containing all the information required by the JAAS
<literal>LoginModule</literal>.</para>
<para>Therefore, the JAAS package for Acegi Security provides two
default callback handlers,
<literal>JaasNameCallbackHandler</literal> and
<literal>JaasPasswordCallbackHandler</literal>. Each of these
callback handlers implement
<literal>JaasAuthenticationCallbackHandler</literal>. In most cases
these callback handlers can simply be used without understanding the
internal mechanics.</para>
<para>For those needing full control over the callback behavior,
internally <literal>JaasAutheticationProvider</literal> wraps these
<literal>JaasAuthenticationCallbackHandler</literal>s with an
<literal>InternalCallbackHandler</literal>. The
<literal>InternalCallbackHandler</literal> is the class that
actually implements JAAS normal <literal>CallbackHandler</literal>
interface. Any time that the JAAS <literal>LoginModule</literal> is
used, it is passed a list of application context configured
<literal>InternalCallbackHandler</literal>s. If the
<literal>LoginModule</literal> requests a callback against the
<literal>InternalCallbackHandler</literal>s, the callback is in-turn
passed to the <literal>JaasAuthenticationCallbackHandler</literal>s
being wrapped.</para>
</sect2>
<sect2 id="jaas-authoritygranter">
<title id="jaas-authority-granter">JAAS AuthorityGranter</title>
<para>JAAS works with principals. Even "roles" are represented as
principals in JAAS. Acegi Security, on the other hand, works with
<literal>Authentication</literal> objects. Each
<literal>Authentication</literal> object contains a single
principal, and multiple <literal>GrantedAuthority</literal>[]s. To
facilitate mapping between these different concepts, Acegi
Security's JAAS package includes an
<literal>AuthorityGranter</literal> interface.</para>
<para>An <literal>AuthorityGranter</literal> is responsible for
inspecting a JAAS principal and returning a
<literal>String</literal>. The
<literal>JaasAuthenticationProvider</literal> then creates a
<literal>JaasGrantedAuthority</literal> (which implements Acegi
Securitys <literal>GrantedAuthority</literal> interface) containing
both the <literal>AuthorityGranter</literal>-returned
<literal>String</literal> and the JAAS principal that the
<literal>AuthorityGranter</literal> was passed. The
<literal>JaasAuthenticationProvider</literal> obtains the JAAS
principals by firstly successfully authenticating the users
credentials using the JAAS <literal>LoginModule</literal>, and then
accessing the <literal>LoginContext</literal> it returns. A call to
<literal>LoginContext.getSubject().getPrincipals()</literal> is
made, with each resulting principal passed to each
<literal>AuthorityGranter</literal> defined against the
<literal>JaasAuthenticationProvider.setAuthorityGranters(List)</literal>
property.</para>
<para>Acegi Security does not include any production
<literal>AuthorityGranter</literal>s given that every JAAS principal
has an implementation-specific meaning. However, there is a
<literal>TestAuthorityGranter</literal> in the unit tests that
demonstrates a simple <literal>AuthorityGranter</literal>
implementation.</para>
</sect2>
</sect1>
</chapter>
<chapter id="siteminder">
<title>Siteminder Authentication Mechanism</title>
<sect1 id="siteminder-overview">
<title>Overview</title>
<para>Siteminder is a commercial single sign on solution by Computer
Associates.</para>
<para>Acegi Security provides a filter,
<literal>SiteminderAuthenticationProcessingFilter</literal> and
provider, <literal>SiteminderAuthenticationProvider</literal> that can
be used to process requests that have been pre-authenticated by
Siteminder. This filter assumes that you're using Siteminder for
<emphasis>authentication</emphasis>, and that you're using Acegi
Security for <emphasis>authorization</emphasis>. The use of Siteminder
for <emphasis>authorization</emphasis> is not yet directly supported
by Acegi Security.</para>
<para>When using Siteminder, an agent is setup on your web server to
intercept a principal's first call to your application. The agent
redirects the web request to a single sign-on login page, and once
authenticated, your application receives the request. Inside the HTTP
request is a header - such as <literal>SM_USER</literal> - which
identifies the authenticated principal (please refer to your
organization's "single sign-on" group for header details in your
particular configuration).</para>
</sect1>
<sect1 id="siteminder-config">
<title>Configuration</title>
<para>The first step in setting up Acegi Security's Siteminder support
is to define the authentication mechanism that will inspect the HTTP
header discussed earlier. It will be responsible for generating a
<literal>UsernamePasswordAuthenticationToken</literal> that is later
sent to the <literal>SiteminderAuthenticationProvider</literal>. Let's
look at an example:</para>
<para><programlisting>&lt;bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.SiteminderAuthenticationProcessingFilter"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="authenticationFailureUrl"&gt;&lt;value&gt;/login.jsp?login_error=1&lt;/value&gt;&lt;/property&gt;
&lt;property name="defaultTargetUrl"&gt;&lt;value&gt;/security.do?method=getMainMenu&lt;/value&gt;&lt;/property&gt;
&lt;property name="filterProcessesUrl"&gt;&lt;value&gt;/j_acegi_security_check&lt;/value&gt;&lt;/property&gt;
&lt;property name="siteminderUsernameHeaderKey"&gt;&lt;value&gt;SM_USER&lt;/value&gt;&lt;/property&gt;
&lt;property name="formUsernameParameterKey"&gt;&lt;value&gt;j_username&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;</programlisting></para>
<para>In our example above, the bean is being provided an
<literal>AuthenticationManager</literal>, as is normally needed by
authentication mechanisms. Several URLs are also specified, with the
values being self-explanatory. It's important to also specify the HTTP
header that Acegi Security should inspect. If you additionally want to
support form-based authentication (i.e. in your development
environment where Siteminder is not installed), specify the form's
username parameter as well - just don't do this in production!</para>
<para>Note that you'll need a
<literal><literal>SiteminderAuthenticationProvider</literal></literal>
configured against your <literal>ProviderManager</literal> in order to
use the Siteminder authentication mechanism. Normally an
<literal>AuthenticationProvider</literal> expects the password
property to match what it retrieves from the
<literal>UserDetailsSource</literal>, but in this case, authentication
has already been handled by Siteminder, so password property is not
even relevant. This may sound like a security weakness, but remember
that users have to authenticate with Siteminder before your
application ever receives the requests, so the purpose of your custom
<literal>UserDetailsService</literal> should simply be to build the
complete <literal>Authentication</literal> object (ie with suitable
<literal>GrantedAuthority[]</literal>s).</para>
<para>Advanced tip and word to the wise: If you additionally want to
support form-based authentication in your development environment
(where Siteminder is typically not installed), specify the form's
username parameter as well. Just don't do this in production!</para>
</sect1>
</chapter>
<chapter id="runas">
<title>Run-As Authentication Replacement</title>
<sect1 id="runas-overview">
<title>Overview</title>
<para>The <literal>AbstractSecurityInterceptor</literal> is able to
temporarily replace the <literal>Authentication</literal> object in
the <literal>SecurityContext</literal> and
<literal>SecurityContextHolder</literal> during the secure object
callback phase. This only occurs if the original
<literal>Authentication</literal> object was successfully processed by
the <literal>AuthenticationManager</literal> and
<literal>AccessDecisionManager</literal>. The
<literal>RunAsManager</literal> will indicate the replacement
<literal>Authentication</literal> object, if any, that should be used
during the <literal>SecurityInterceptorCallback</literal>.</para>
<para>By temporarily replacing the <literal>Authentication</literal>
object during the secure object callback phase, the secured invocation
will be able to call other objects which require different
authentication and authorization credentials. It will also be able to
perform any internal security checks for specific
<literal>GrantedAuthority</literal> objects. Because Acegi Security
provides a number of helper classes that automatically configure
remoting protocols based on the contents of the
<literal>SecurityContextHolder</literal>, these run-as replacements
are particularly useful when calling remote web services</para>
</sect1>
<sect1 id="runas-config">
<title>Configuration</title>
<para>A <literal>RunAsManager</literal> interface is provided by Acegi
Security:</para>
<para><programlisting>public Authentication buildRunAs(Authentication authentication, Object object, ConfigAttributeDefinition config);
public boolean supports(ConfigAttribute attribute);
public boolean supports(Class clazz);</programlisting></para>
<para>The first method returns the <literal>Authentication</literal>
object that should replace the existing
<literal>Authentication</literal> object for the duration of the
method invocation. If the method returns <literal>null</literal>, it
indicates no replacement should be made. The second method is used by
the <literal>AbstractSecurityInterceptor</literal> as part of its
startup validation of configuration attributes. The
<literal>supports(Class)</literal> method is called by a security
interceptor implementation to ensure the configured
<literal>RunAsManager</literal> supports the type of secure object
that the security interceptor will present.</para>
<para>One concrete implementation of a <literal>RunAsManager</literal>
is provided with Acegi Security. The
<literal>RunAsManagerImpl</literal> class returns a replacement
<literal>RunAsUserToken</literal> if any
<literal>ConfigAttribute</literal> starts with
<literal>RUN_AS_</literal>. If any such
<literal>ConfigAttribute</literal> is found, the replacement
<literal>RunAsUserToken</literal> will contain the same principal,
credentials and granted authorities as the original
<literal>Authentication</literal> object, along with a new
<literal>GrantedAuthorityImpl</literal> for each
<literal>RUN_AS_</literal> <literal>ConfigAttribute</literal>. Each
new <literal>GrantedAuthorityImpl</literal> will be prefixed with
<literal>ROLE_</literal>, followed by the <literal>RUN_AS</literal>
<literal>ConfigAttribute</literal>. For example, a
<literal>RUN_AS_SERVER</literal> will result in the replacement
<literal>RunAsUserToken</literal> containing a
<literal>ROLE_RUN_AS_SERVER</literal> granted authority.</para>
<para>The replacement <literal>RunAsUserToken</literal> is just like
any other <literal>Authentication</literal> object. It needs to be
authenticated by the <literal>AuthenticationManager</literal>,
probably via delegation to a suitable
<literal>AuthenticationProvider</literal>. The
<literal>RunAsImplAuthenticationProvider</literal> performs such
authentication. It simply accepts as valid any
<literal>RunAsUserToken</literal> presented.</para>
<para>To ensure malicious code does not create a
<literal>RunAsUserToken</literal> and present it for guaranteed
acceptance by the <literal>RunAsImplAuthenticationProvider</literal>,
the hash of a key is stored in all generated tokens. The
<literal>RunAsManagerImpl</literal> and
<literal>RunAsImplAuthenticationProvider</literal> is created in the
bean context with the same key:</para>
<para><programlisting>
&lt;bean id="runAsManager" class="org.acegisecurity.runas.RunAsManagerImpl"&gt;
&lt;property name="key"&gt;&lt;value&gt;my_run_as_password&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="runAsAuthenticationProvider" class="org.acegisecurity.runas.RunAsImplAuthenticationProvider"&gt;
&lt;property name="key"&gt;&lt;value&gt;my_run_as_password&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting></para>
<para>By using the same key, each <literal>RunAsUserToken</literal>
can be validated it was created by an approved
<literal>RunAsManagerImpl</literal>. The
<literal>RunAsUserToken</literal> is immutable after creation for
security reasons</para>
</sect1>
</chapter>
<chapter id="form">
<title>Form Authentication Mechanism</title>
<sect1 id="form-overview">
<title>Overview</title>
<para>HTTP Form Authentication involves using the
<literal>AuthenticationProcessingFilter</literal> to process a login
form. This is the most common way that application authenticate end
users. Form-based authentication is entirely compatible with the DAO
and JAAS authentication providers.</para>
</sect1>
<sect1 id="form-config">
<title>Configuration</title>
<para>The login form simply contains <literal>j_username</literal> and
<literal>j_password</literal> input fields, and posts to a URL that is
monitored by the filter (by default
<literal>j_acegi_security_check</literal>). The filter is defined in
<literal>web.xml</literal> behind a
<literal>FilterToBeanProxy</literal> as follows:</para>
<para><programlisting>&lt;filter&gt;
&lt;filter-name&gt;Acegi Authentication Processing Filter&lt;/filter-name&gt;
&lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;targetClass&lt;/param-name&gt;
&lt;param-value&gt;org.acegisecurity.ui.webapp.AuthenticationProcessingFilter&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;Acegi Authentication Processing Filter&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;</programlisting></para>
<para>For a discussion of <literal>FilterToBeanProxy</literal>, please
refer to the Filters section. The application context will need to
define the <literal>AuthenticationProcessingFilter</literal>:</para>
<para><programlisting>&lt;bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="authenticationFailureUrl"&gt;&lt;value&gt;/acegilogin.jsp?login_error=1&lt;/value&gt;&lt;/property&gt;
&lt;property name="defaultTargetUrl"&gt;&lt;value&gt;/&lt;/value&gt;&lt;/property&gt;
&lt;property name="filterProcessesUrl"&gt;&lt;value&gt;/j_acegi_security_check&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>The configured <literal>AuthenticationManager</literal>
processes each authentication request. If authentication fails, the
browser will be redirected to the
<literal>authenticationFailureUrl</literal>. The
<literal>AuthenticationException</literal> will be placed into the
<literal>HttpSession</literal> attribute indicated by
<literal>AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY</literal>,
enabling a reason to be provided to the user on the error page.</para>
<para>If authentication is successful, the resulting
<literal>Authentication</literal> object will be placed into the
<literal>SecurityContextHolder</literal>.</para>
<para>Once the <literal>SecurityContextHolder</literal> has been
updated, the browser will need to be redirected to the target URL. The
target URL is usually indicated by the <literal>HttpSession</literal>
attribute specified by
<literal>AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY</literal>.
This attribute is automatically set by the
<literal>ExceptionTranslationFilter</literal> when an
<literal>AuthenticationException</literal> occurs, so that after login
is completed the user can return to what they were trying to access.
If for some reason the <literal>HttpSession</literal> does not
indicate the target URL, the browser will be redirected to the
<literal>defaultTargetUrl</literal> property.</para>
</sect1>
</chapter>
<chapter id="basic">
<title>BASIC Authentication Mechanism</title>
<sect1 id="basic-overview">
<title>Overview</title>
<para>Acegi Security provides a
<literal>BasicProcessingFilter</literal> which is capable of
processing basic authentication credentials presented in HTTP headers.
This can be used for authenticating calls made by Spring remoting
protocols (such as Hessian and Burlap), as well as normal user agents
(such as Internet Explorer and Navigator). The standard governing HTTP
Basic Authentication is defined by RFC 1945, Section 11, and the
<literal>BasicProcessingFilter</literal> conforms with this RFC. Basic
Authentication is an attractive approach to authentication, because it
is very widely deployed in user agents and implementation is extremely
simple (it's just a Base64 encoding of the username:password,
specified in a HTTP header).</para>
</sect1>
<sect1 id="basic-config">
<title>Configuration</title>
<para>To implement HTTP Basic Authentication, it is necessary to
define <literal>BasicProcessingFilter</literal> in the filter chain.
The application context will need to define the
<literal>BasicProcessingFilter</literal> and its required
collaborator:</para>
<para><programlisting>
&lt;bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="authenticationEntryPoint"&gt;&lt;ref bean="authenticationEntryPoint"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="authenticationEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint"&gt;
&lt;property name="realmName"&gt;&lt;value&gt;Name Of Your Realm&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting></para>
<para>The configured <literal>AuthenticationManager</literal>
processes each authentication request. If authentication fails, the
configured <literal>AuthenticationEntryPoint</literal> will be used to
retry the authentication process. Usually you will use the
<literal>BasicProcessingFilterEntryPoint</literal>, which returns a
401 response with a suitable header to retry HTTP Basic
authentication. If authentication is successful, the resulting
<literal>Authentication</literal> object will be placed into the
<literal>SecurityContextHolder</literal>.</para>
<para>If the authentication event was successful, or authentication
was not attempted because the HTTP header did not contain a supported
authentication request, the filter chain will continue as normal. The
only time the filter chain will be interrupted is if authentication
fails and the <literal>AuthenticationEntryPoint</literal> is called,
as discussed in the previous paragraph</para>
</sect1>
</chapter>
<chapter id="digest">
<title>Digest Authentication</title>
<sect1 id="digest-overview">
<title>Overview</title>
<para>Acegi Security provides a
<literal>DigestProcessingFilter</literal> which is capable of
processing digest authentication credentials presented in HTTP
headers. Digest Authentication attempts to solve many of the
weaknesses of Basic authentication, specifically by ensuring
credentials are never sent in clear text across the wire. Many user
agents support Digest Authentication, including FireFox and Internet
Explorer. The standard governing HTTP Digest Authentication is defined
by RFC 2617, which updates an earlier version of the Digest
Authentication standard prescribed by RFC 2069. Most user agents
implement RFC 2617. Acegi Security
<literal>DigestProcessingFilter</literal> is compatible with the
"<literal>auth</literal>" quality of protection
(<literal>qop</literal>) prescribed by RFC 2617, which also provides
backward compatibility with RFC 2069. Digest Authentication is a
highly attractive option if you need to use unencrypted HTTP (ie no
TLS/HTTPS) and wish to maximise security of the authentication
process. Indeed Digest Authentication is a mandatory requirement for
the WebDAV protocol, as noted by RFC 2518 Section 17.1, so we should
expect to see it increasingly deployed and replacing Basic
Authentication.</para>
<para>Digest Authentication is definitely the most secure choice
between Form Authentication, Basic Authentication and Digest
Authentication, although extra security also means more complex user
agent implementations. Central to Digest Authentication is a "nonce".
This is a value the server generates. Acegi Security's nonce adopts
the following format:</para>
<para><programlisting>base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
expirationTime: The date and time when the nonce expires, expressed in milliseconds
key: A private key to prevent modification of the nonce token
</programlisting></para>
<para>The <literal>DigestProcessingFilterEntryPoint</literal> has a
property specifying the <literal>key</literal> used for generating the
nonce tokens, along with a <literal>nonceValiditySeconds</literal>
property for determining the expiration time (default 300, which
equals five minutes). Whist ever the nonce is valid, the digest is
computed by concatenating various strings including the username,
password, nonce, URI being requested, a client-generated nonce (merely
a random value which the user agent generates each request), the realm
name etc, then performing an MD5 hash. Both the server and user agent
perform this digest computation, resulting in different hash codes if
they disagree on an included value (eg password). In Acegi Security
implementation, if the server-generated nonce has merely expired (but
the digest was otherwise valid), the
<literal>DigestProcessingFilterEntryPoint</literal> will send a
<literal>"stale=true"</literal> header. This tells the user agent
there is no need to disturb the user (as the password and username etc
is correct), but simply to try again using a new nonce.</para>
<para>An appropriate value for
<literal>DigestProcessingFilterEntryPoint</literal>'s
<literal>nonceValiditySeconds</literal> parameter will depend on your
application. Extremely secure applications should note that an
intercepted authentication header can be used to impersonate the
principal until the <literal>expirationTime</literal> contained in the
nonce is reached. This is the key principle when selecting an
appropriate setting, but it would be unusual for immensely secure
applications to not be running over TLS/HTTPS in the first
instance.</para>
<para>Because of the more complex implementation of Digest
Authentication, there are often user agent issues. For example,
Internet Explorer fails to present an "<literal>opaque</literal>"
token on subsequent requests in the same session. Acegi Security
filters therefore encapsulate all state information into the
"<literal>nonce</literal>" token instead. In our testing, Acegi
Security implementation works reliably with FireFox and Internet
Explorer, correctly handling nonce timeouts etc.</para>
</sect1>
<sect1 id="digest-config">
<title>Configuration</title>
<para>Now that we've reviewed the theory, let's see how to use it. To
implement HTTP Digest Authentication, it is necessary to define
<literal>DigestProcessingFilter</literal> in the fitler chain. The
application context will need to define the
<literal>DigestProcessingFilter</literal> and its required
collaborators:</para>
<para><programlisting>
&lt;bean id="digestProcessingFilter" class="org.acegisecurity.ui.digestauth.DigestProcessingFilter"&gt;
&lt;property name="userDetailsService"&gt;&lt;ref local="jdbcDaoImpl"/&gt;&lt;/property&gt;
&lt;property name="authenticationEntryPoint"&gt;&lt;ref local="digestProcessingFilterEntryPoint"/&gt;&lt;/property&gt;
&lt;property name="userCache"&gt;&lt;ref local="userCache"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="digestProcessingFilterEntryPoint" class="org.acegisecurity.ui.digestauth.DigestProcessingFilterEntryPoint"&gt;
&lt;property name="realmName"&gt;&lt;value&gt;Contacts Realm via Digest Authentication&lt;/value&gt;&lt;/property&gt;
&lt;property name="key"&gt;&lt;value&gt;acegi&lt;/value&gt;&lt;/property&gt;
&lt;property name="nonceValiditySeconds"&gt;&lt;value&gt;10&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting></para>
<para>The configured <literal>UserDetailsService</literal> is needed
because <literal>DigestProcessingFilter</literal> must have direct
access to the clear text password of a user. Digest Authentication
will NOT work if you are using encoded passwords in your DAO. The DAO
collaborator, along with the <literal>UserCache</literal>, are
typically shared directly with a
<literal>DaoAuthenticationProvider</literal>. The
<literal>authenticationEntryPoint</literal> property must be
<literal>DigestProcessingFilterEntryPoint</literal>, so that
<literal>DigestProcessingFilter</literal> can obtain the correct
<literal>realmName</literal> and <literal>key</literal> for digest
calculations.</para>
<para>Like <literal>BasicAuthenticationFilter</literal>, if
authentication is successful an <literal>Authentication</literal>
request token will be placed into the
<literal>SecurityContextHolder</literal>. If the authentication event
was successful, or authentication was not attempted because the HTTP
header did not contain a Digest Authentication request, the filter
chain will continue as normal. The only time the filter chain will be
interrupted is if authentication fails and the
<literal>AuthenticationEntryPoint</literal> is called, as discussed in
the previous paragraph.</para>
<para>Digest Authentication's RFC offers a range of additional
features to further increase security. For example, the nonce can be
changed on every request. Despite this, Acegi Security implementation
was designed to minimise the complexity of the implementation (and the
doubtless user agent incompatibilities that would emerge), and avoid
needing to store server-side state. You are invited to review RFC 2617
if you wish to explore these features in more detail. As far as we are
aware, Acegi Security implementation does comply with the minimum
standards of this RFC.</para>
</sect1>
</chapter>
<chapter id="anonymous">
<title>Anonymous Authentication</title>
<sect1 id="anonymous-overview">
<title>Overview</title>
<para>Particularly in the case of web request URI security, sometimes
it is more convenient to assign configuration attributes against every
possible secure object invocation. Put differently, sometimes it is
nice to say <literal>ROLE_SOMETHING</literal> is required by default
and only allow certain exceptions to this rule, such as for login,
logout and home pages of an application. There are also other
situations where anonymous authentication would be desired, such as
when an auditing interceptor queries the
<literal>SecurityContextHolder</literal> to identify which principal
was responsible for a given operation. Such classes can be authored
with more robustness if they know the
<literal>SecurityContextHolder</literal> always contains an
<literal>Authentication</literal> object, and never
<literal>null</literal>.</para>
</sect1>
<sect1 id="anonymous-config">
<title>Configuration</title>
<para>Acegi Security provides three classes that together provide an
anonymous authentication feature.
<literal>AnonymousAuthenticationToken</literal> is an implementation
of <literal>Authentication</literal>, and stores the
<literal>GrantedAuthority</literal>[]s which apply to the anonymous
principal. There is a corresponding
<literal>AnonymousAuthenticationProvider</literal>, which is chained
into the <literal>ProviderManager</literal> so that
<literal>AnonymousAuthenticationTokens</literal> are accepted.
Finally, there is an AnonymousProcessingFilter, which is chained after
the normal authentication mechanisms and automatically add an
<literal>AnonymousAuthenticationToken</literal> to the
<literal>SecurityContextHolder</literal> if there is no existing
<literal>Authentication</literal> held there. The definition of the
filter and authentication provider appears as follows:</para>
<para><programlisting>
&lt;bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter"&gt;
&lt;property name="key"&gt;&lt;value&gt;foobar&lt;/value&gt;&lt;/property&gt;
&lt;property name="userAttribute"&gt;&lt;value&gt;anonymousUser,ROLE_ANONYMOUS&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="anonymousAuthenticationProvider" class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"&gt;
&lt;property name="key"&gt;&lt;value&gt;foobar&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting></para>
<para>The <literal>key</literal> is shared between the filter and
authentication provider, so that tokens created by the former are
accepted by the latter. The <literal>userAttribute</literal> is
expressed in the form of
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
This is the same syntax as used after the equals sign for
<literal>InMemoryDaoImpl</literal>'s <literal>userMap</literal>
property.</para>
<para>As explained earlier, the benefit of anonymous authentication is
that all URI patterns can have security applied to them. For
example:</para>
<para><programlisting>
&lt;bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="accessDecisionManager"&gt;&lt;ref local="httpRequestAccessDecisionManager"/&gt;&lt;/property&gt;
&lt;property name="objectDefinitionSource"&gt;
&lt;value&gt;
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/index.jsp=ROLE_ANONYMOUS,ROLE_USER
/hello.htm=ROLE_ANONYMOUS,ROLE_USER
/logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
/acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER
/**=ROLE_USER
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
</programlisting>Rounding out the anonymous authentication discussion
is the <literal>AuthenticationTrustResolver</literal> interface, with
its corresponding <literal>AuthenticationTrustResolverImpl</literal>
implementation. This interface provides an
<literal>isAnonymous(Authentication)</literal> method, which allows
interested classes to take into account this special type of
authentication status. The
<literal>ExceptionTranslationFilter</literal> uses this interface in
processing <literal>AccessDeniedException</literal>s. If an
<literal>AccessDeniedException</literal> is thrown, and the
authentication is of an anonymous type, instead of throwing a 403
(forbidden) response, the filter will instead commence the
<literal>AuthenticationEntryPoint</literal> so the principal can
authenticate properly. This is a necessary distinction, otherwise
principals would always be deemed "authenticated" and never be given
an opportunity to login via form, basic, digest or some other normal
authentication mechanism</para>
</sect1>
</chapter>
<chapter id="remember-me">
<title>Remember-Me Authentication</title>
<sect1 id="remember-me-overview">
<title>Overview</title>
<para>Remember-me authentication refers to web sites being able to
remember the identity of a principal between sessions. This is
typically accomplished by sending a cookie to the browser, with the
cookie being detected during future sessions and causing automated
login to take place. Acegi Security provides the necessary hooks so
that such operations can take place, along with providing a concrete
implementation that uses hashing to preserve the security of
cookie-based tokens.</para>
</sect1>
<sect1 id="remember-me-config">
<title>Configuration</title>
<para>Remember-me authentication is not used with basic
authentication, given it is often not used with
<literal>HttpSession</literal>s. Remember-me is used with
<literal>AuthenticationProcessingFilter</literal>, and is implemented
via hooks in the <literal>AbstractProcessingFilter</literal>
superclass. The hooks will invoke a concrete
<literal>RememberMeServices</literal> at the appropriate times. The
interface looks like this:</para>
<para><programlisting>public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
public void loginFail(HttpServletRequest request, HttpServletResponse response);
public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication);</programlisting></para>
<para>Please refer to JavaDocs for a fuller discussion on what the
methods do, although note at this stage
<literal>AbstractProcessingFilter</literal> only calls the
<literal>loginFail()</literal> and <literal>loginSuccess()</literal>
methods. The <literal>autoLogin()</literal> method is called by
<literal>RememberMeProcessingFilter</literal> whenever the
<literal>SecurityContextHolder</literal> does not contain an
<literal>Authentication</literal>. This interface therefore provides
the underlaying remember-me implementation with sufficient
notification of authentication-related events, and delegates to the
implementation whenever a candidate web request might contain a cookie
and wish to be remembered.</para>
<para>This design allows any number of remember-me implementation
strategies. In the interests of simplicity and avoiding the need for
DAO implementations that specify write and create methods, Acegi
Security's only concrete implementation,
<literal>TokenBasedRememberMeServices</literal>, uses hashing to
achieve a useful remember-me strategy. In essence a cookie is sent to
the browser upon successful interactive authentication, with that
cookie being composed as follows:</para>
<para><programlisting>base64(username + ":" + expirationTime + ":" + md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
username: As identifiable to TokenBasedRememberMeServices.getUserDetailsService()
password: That matches the relevant UserDetails retrieved from TokenBasedRememberMeServices.getUserDetailsService()
expirationTime: The date and time when the remember-me token expires, expressed in milliseconds
key: A private key to prevent modification of the remember-me token
</programlisting></para>
<para>As such the remember-me token is valid only for the period
specified, and provided that the username, password and key does not
change. Notably, this has a potential security issue in that a
captured remember-me token will be usable from any user agent until
such time as the token expires. This is the same issue as with digest
authentication. If a principal is aware a token has been captured,
they can easily change their password and immediately invalidate all
remember-me tokens on issue. However, if more significant security is
needed a rolling token approach should be used (this would require a
database) or remember-me services should simply not be used.</para>
<para><literal>TokenBasedRememberMeServices</literal> generates a
<literal>RememberMeAuthenticationToken</literal>, which is processed
by <literal>RememberMeAuthenticationProvider</literal>. A
<literal>key</literal> is shared between this authentication provider
and the <literal>TokenBasedRememberMeServices</literal>. In addition,
<literal>TokenBasedRememberMeServices</literal> requires A
UserDetailsService from which it can retrieve the username and
password for signature comparison purposes, and generate the
<literal>RememberMeAuthenticationToken</literal> to contain the
correct <literal>GrantedAuthority</literal>[]s. Some sort of logout
command should be provided by the application (typically via a JSP)
that invalidates the cookie upon user request. See the Contacts Sample
application's <literal>logout.jsp</literal> for an example.</para>
<para>The beans required in an application context to enable
remember-me services are as follows:</para>
<para><programlisting>
&lt;bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"&gt;
&lt;property name="rememberMeServices"&gt;&lt;ref local="rememberMeServices"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices"&gt;
&lt;property name="userDetailsService"&gt;&lt;ref local="jdbcDaoImpl"/&gt;&lt;/property&gt;
&lt;property name="key"&gt;&lt;value&gt;springRocks&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="rememberMeAuthenticationProvider" class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"&gt;
&lt;property name="key"&gt;&lt;value&gt;springRocks&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting>Don't forget to add your
<literal>RememberMeServices</literal> implementation to your
<literal>AuthenticationProcessingFilter.setRememberMeServices()</literal>
property, include the
<literal>RememberMeAuthenticationProvider</literal> in your
<literal>AuthenticationManager.setProviders()</literal> list, and add
a call to <literal>RememberMeProcessingFilter</literal> into your
<literal>FilterChainProxy</literal> (typically immediately after your
<literal>AuthenticationProcessingFilter</literal>)</para>
</sect1>
</chapter>
<chapter id="x509">
<title>X509 Authentication</title>
<sect1 id="x509-overview">
<title>Overview</title>
<para>The most common use of X509 certificate authentication is in
verifying the identity of a server when using SSL, most commonly when
using HTTPS from a browser. The browser will automatically check that
the certificate presented by a server has been issued (ie digitally
signed) by one of a list of trusted certificate authorities which it
maintains.</para>
<para>You can also use SSL with <quote>mutual authentication</quote>;
the server will then request a valid certificate from the client as
part of the SSL handshake. The server will authenticate the client by
checking that it's certificate is signed by an acceptable authority.
If a valid certificate has been provided, it can be obtained through
the servlet API in an application. Acegi Security X509 module extracts
the certificate using a filter and passes it to the configured X509
authentication provider to allow any additional application-specific
checks to be applied. It also maps the certificate to an application
user and loads that user's set of granted authorities for use with the
standard Acegi Security infrastructure.</para>
<para>You should be familiar with using certificates and setting up
client authentication for your servlet container before attempting to
use it with Acegi Security. Most of the work is in creating and
installing suitable certificates and keys. For example, if you're
using Tomcat then read the instructions here <ulink
url="http://jakarta.apache.org/tomcat/tomcat-5.0-doc/ssl-howto.html"></ulink>.
It's important that you get this working before trying it out with
Acegi Security</para>
</sect1>
<sect1 id="x509-with-acegi">
<title>Using X509 with Acegi Security</title>
<para>With X509 authentication, there is no explicit login procedure
so the implementation is relatively simple; there is no need to
redirect requests in order to interact with the user. As a result,
some of the classes behave slightly differently from their equivalents
in other packages. For example, the default <quote>entry point</quote>
class, which is normally responsible for starting the authentication
process, is only invoked if the certificate is rejected and it always
returns an error to the user. With a suitable bean configuration, the
normal sequence of events is as follows <orderedlist>
<listitem>
<para>The <classname>X509ProcessingFilter</classname> extracts
the certificate from the request and uses it as the credentials
for an authentication request. The generated authentication
request is an <classname>X509AuthenticationToken</classname>.
The request is passed to the authentication manager.</para>
</listitem>
<listitem>
<para>The <classname>X509AuthenticationProvider</classname>
receives the token. Its main concern is to obtain the user
information (in particular the user's granted authorities) that
matches the certificate. It delegates this responsibility to an
<interfacename>X509AuthoritiesPopulator</interfacename>.</para>
</listitem>
<listitem>
<para>The populator's single method,
<methodname>getUserDetails(X509Certificate
userCertificate)</methodname> is invoked. Implementations should
return a <classname>UserDetails</classname> instance containing
the array of <classname>GrantedAuthority</classname> objects for
the user. This method can also choose to reject the certificate
(for example if it doesn't contain a matching user name). In
such cases it should throw a
<exceptionname>BadCredentialsException</exceptionname>. A
DAO-based implementation,
<classname>DaoX509AuthoritiesPopulator</classname>, is provided
which extracts the user's name from the subject <quote>common
name</quote> (CN) in the certificate. It also allows you to set
your own regular expression to match a different part of the
subject's distinguished name. A UserDetailsService is used to
load the user information.<!-- TODO: Give email matching as an example --></para>
</listitem>
<listitem>
<para>If everything has gone smoothly then there should be a
valid <classname>Authentication</classname> object in the secure
context and the invocation will procede as normal. If no
certificate was found, or the certificate was rejected, then the
<classname>ExceptionTranslationFilter</classname> will invoke
the <classname>X509ProcessingFilterEntryPoint</classname> which
returns a 403 error (forbidden) to the user.</para>
</listitem>
</orderedlist></para>
</sect1>
<sect1 id="x509-config">
<title>Configuration</title>
<para>There is a version of the <link
linkend="contacts-sample">Contacts Sample Application</link> which
uses X509. Copy the beans and filter setup from this as a starting
point for configuring your own application. A set of example
certificates is also included which you can use to configure your
server. These are <itemizedlist>
<listitem>
<para><filename>marissa.p12</filename>: A PKCS12 format file
containing the client key and certificate. These should be
installed in your browser. It maps to the user
<quote>marissa</quote> in the application.</para>
</listitem>
<listitem>
<para><filename>server.p12</filename>: The server certificate
and key for HTTPS connections.</para>
</listitem>
<listitem>
<para><filename>ca.jks</filename>: A Java keystore containing
the certificate for the authority which issued marissa's
certificate. This will be used by the container to validate
client certificates.</para>
</listitem>
</itemizedlist> For JBoss 3.2.7 (with Tomcat 5.0), the SSL
configuration in the <filename>server.xml</filename> file looks like
this <programlisting>
&lt;!-- SSL/TLS Connector configuration --&gt;
&lt;Connector port="8443" address="${jboss.bind.address}"
maxThreads="100" minSpareThreads="5" maxSpareThreads="15"
scheme="https" secure="true"
sslProtocol = "TLS"
clientAuth="true" keystoreFile="${jboss.server.home.dir}/conf/server.p12"
keystoreType="PKCS12" keystorePass="password"
truststoreFile="${jboss.server.home.dir}/conf/ca.jks"
truststoreType="JKS" truststorePass="password"
/&gt;
</programlisting><parameter>clientAuth</parameter> can also be set to
<parameter>want</parameter> if you still want SSL connections to
succeed even if the client doesn't provide a certificate. Obviously
these clients won't be able to access any objects secured by Acegi
Security (unless you use a non-X509 authentication mechanism, such as
BASIC authentication, to authenticate the user)</para>
</sect1>
</chapter>
<chapter id="ldap">
<title>LDAP Authentication</title>
<sect1 id="ldap-overview">
<title>Overview</title>
<para>LDAP is often used by organizations as a central repository for
user information and as an authentication service. It can also be used
to store the role information for application users.</para>
<para>There are many different scenarios for how an LDAP server may be
configured so Acegi LDAP provider is fully configurable. It uses
separate strategy interfaces for authentication and role retrieval and
provides default implementations which can be configured to handle a
wide range of situations.</para>
<para>You should be familiar with LDAP before trying to use it with
Acegi. The following link provides a good introduction to the concepts
involved and a guide to setting up a directory using the free LDAP
server OpenLDAP: <ulink
url="http://www.zytrax.com/books/ldap/"></ulink>. Some familiarity
with the JNDI APIs used to access LDAP from Java may also be useful.
We don't use any third-party LDAP libraries (Mozilla/Netscape, JLDAP
etc.) in the LDAP provider.</para>
</sect1>
<sect1 id="ldap-with-acegi">
<title>Using LDAP with Acegi Security</title>
<para>The main LDAP provider class is
<classname>org.acegisecurity.providers.ldap.LdapAuthenticationProvider</classname>.
This bean doesn't actually do much itself other than implement the
<methodname>retrieveUser</methodname> method required by its base
class,
<classname>AbstractUserDetailsAuthenticationProvider</classname>. It
delegates the work to two other beans, an
<interfacename>LdapAuthenticator</interfacename> and an
<interfacename>LdapAuthoritiesPopulator</interfacename> which are
responsible for authenticating the user and retrieving the user's set
of <interfacename>GrantedAuthority</interfacename>s
respectively.</para>
<sect2 id="ldap-ldap-authenticators">
<title>LdapAuthenticator Implementations</title>
<para>The authenticator is also responsible for retrieving any
required user attributes. This is because the permissions on the
attributes may depend on the type of authentication being used. For
example, if binding as the user, it may be necessary to read them
with the user's own permissions.</para>
<para>There are currently two authentication strategies supplied
with Acegi Security: <itemizedlist>
<listitem>
<para>Authentication directly to the LDAP server ("bind"
authentication).</para>
</listitem>
<listitem>
<para>Password comparison, where the password supplied by the
user is compared with the one stored in the repository. This
can either be done by retrieving the value of the password
attribute and checking it locally or by performing an LDAP
"compare" operation, where the supplied password is passed to
the server for comparison and the real password value is never
retrieved.</para>
</listitem>
</itemizedlist></para>
<sect3 id="ldap-ldap-authenticators-common">
<title>Common Functionality</title>
<para>Before it is possible to authenticate a user (by either
strategy), the distinguished name (DN) has to be obtained from the
login name supplied to the application. This can be done either by
simple pattern-matching (by setting the
<property>setUserDnPatterns</property> array property) or by
setting the <property>userSearch</property> property. For the DN
pattern-matching approach, a standard Java pattern format is used,
and the login name will be substituted for the parameter
<parameter>{0}</parameter>. The pattern should be relative to the
DN that the configured
<interfacename>InitialDirContextFactory</interfacename> will bind
to (see the section on <link
linkend="ldap-dircontextfactory">connecting to the LDAP
server</link> for more information on this). For example, if you
are using an LDAP server specified by the URL
<literal>ldap://monkeymachine.co.uk/dc=acegisecurity,dc=org</literal>,
and have a pattern <literal>uid={0},ou=greatapes</literal>, then a
login name of "gorilla" will map to a DN
<literal>uid=gorilla,ou=greatapes,dc=acegisecurity,dc=org</literal>.
Each configured DN pattern will be tried in turn until a match is
found. For information on using a search, see the section on <link
linkend="ldap-searchobjects">search objects</link> below. A
combination of the two approaches can also be used - the patterns
will be checked first and if no matching DN is found, the search
will be used.</para>
</sect3>
<sect3 id="ldap-ldap-authenticators-bind">
<title>BindAuthenticator</title>
<para>The class
<classname>org.acegisecurity.providers.ldap.authenticator.BindAuthenticator</classname>
implements the bind authentication strategy. It simply attempts to
bind as the user.</para>
</sect3>
<sect3 id="ldap-ldap-authenticators-password">
<title>PasswordComparisonAuthenticator</title>
<para>The class
<classname>org.acegisecurity.providers.ldap.authenticator.PasswordComparisonAuthenticator</classname>
implements the password comparison authentication strategy.</para>
</sect3>
<sect3 id="ldap-ldap-authenticators-active-directory">
<title>Active Directory Authentication</title>
<para>In addition to standard LDAP authentication (binding with a
DN), Active Directory has its own non-standard syntax for user
authentication.</para>
</sect3>
</sect2>
<sect2 id="ldap-dircontextfactory">
<title>Connecting to the LDAP Server</title>
<para>The beans discussed above have to be able to connect to the
server. They both have to be supplied with an
<interfacename>InitialDirContextFactory</interfacename> instance.
Unless you have special requirements, this will usually be a
<classname>DefaultInitialDirContextFactory</classname> bean, which
can be configured with the URL of your LDAP server and optionally
with the username and password of a "manager" user which will be
used by default when binding to the server (instead of binding
anonymously). It currently supports "simple" LDAP
authentication.</para>
<para><classname>DefaultInitialDirContextFactory</classname> uses
Sun's JNDI LDAP implementation by default (the one that comes with
the JDK). It also supports the built in connection pooling offered
by Sun's provider. Connections which are obtained either anonymously
or with the "manager" user's identity will be pooled automatically.
Connections obtained with a specific user's identity will not be
pooled. Connection pooling can be disabled completely by setting the
<property>useConnectionPool</property> property to false.</para>
<para>See the <ulink
url="http://acegisecurity.org/multiproject/acegi-security/xref/org/acegisecurity/providers/ldap/DefaultInitialDirContextFactory.html">class
Javadoc and source</ulink> for more information on this bean and its
properties.</para>
</sect2>
<sect2 id="ldap-searchobjects">
<title>LDAP Search Objects</title>
<para>Often more a more complicated strategy than simple DN-matching
is required to locate a user entry in the directory. This can be
encapsulated in an <interfacename>LdapUserSearch</interfacename>
instance which can be supplied to the authenticator implementations,
for example, to allow them to locate a user. The supplied
implementation is
<classname>FilterBasedLdapUserSearch</classname>.</para>
<sect3 id="ldap-searchobjects-filter">
<title
id="ldap-searchobjects-filter-based"><classname>FilterBasedLdapUserSearch</classname></title>
<para>This bean uses an LDAP filter to match the user object in
the directory. The process is explained in the Javadoc for the
corresponding search method on the <ulink
url="http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/directory/DirContext.html#search(javax.naming.Name,%20java.lang.String,%20java.lang.Object[],%20javax.naming.directory.SearchControls)">JDK
DirContext class</ulink>. As explained there, the search filter
can be supplied with parameters. For this class, the only valid
parameter is <parameter>{0}</parameter> which will be replaced
with the user's login name.</para>
</sect3>
</sect2>
</sect1>
<sect1 id="ldap-config">
<title>Configuration</title>
<para>There is a version of the <link
linkend="contacts-sample">Contacts Sample Application</link> which
uses LDAP. You can copy the beans and filter setup from this as a
starting point for configuring your own application.</para>
<para>A typical configuration, using some of the beans we've discussed
above, might look like this: <programlisting>
&lt;bean id="initialDirContextFactory"
class="org.acegisecurity.ldap.DefaultInitialDirContextFactory"&gt;
&lt;constructor-arg value="ldap://monkeymachine:389/dc=acegisecurity,dc=org"/&gt;
&lt;property name="managerDn"&gt;&lt;value&gt;cn=manager,dc=acegisecurity,dc=org&lt;/value&gt;&lt;/property&gt;
&lt;property name="managerPassword"&gt;&lt;value&gt;password&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="userSearch"
class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch"&gt;
&lt;constructor-arg index="0"&gt;
&lt;value&gt;&lt;/value&gt;
&lt;/constructor-arg&gt;
&lt;constructor-arg index="1"&gt;
&lt;value&gt;(uid={0})&lt;/value&gt;
&lt;/constructor-arg&gt;
&lt;constructor-arg index="2"&gt;
&lt;ref local="initialDirContextFactory" /&gt;
&lt;/constructor-arg&gt;
&lt;property name="searchSubtree"&gt;
&lt;value&gt;true&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="ldapAuthProvider"
class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider"&gt;
&lt;constructor-arg&gt;
&lt;bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator"&gt;
&lt;constructor-arg&gt;&lt;ref local="initialDirContextFactory"/&gt;&lt;/constructor-arg&gt;
&lt;property name="userDnPatterns"&gt;&lt;list&gt;&lt;value&gt;uid={0},ou=people&lt;/value&gt;&lt;/list&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;/constructor-arg&gt;
&lt;constructor-arg&gt;
&lt;bean class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator"&gt;
&lt;constructor-arg&gt;&lt;ref local="initialDirContextFactory"/&gt;&lt;/constructor-arg&gt;
&lt;constructor-arg&gt;&lt;value&gt;ou=groups&lt;/value&gt;&lt;/constructor-arg&gt;
&lt;property name="groupRoleAttribute"&gt;&lt;value&gt;ou&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;/constructor-arg&gt;
&lt;/bean&gt;
</programlisting> This would set up the provider to access an LDAP
server with URL
<literal>ldap://monkeymachine:389/dc=acegisecurity,dc=org</literal>.
Authentication will be performed by attempting to bind with the DN
<literal>uid=&lt;user-login-name&gt;,ou=people,dc=acegisecurity,dc=org</literal>.
After successful authentication, roles will be assigned to the user by
searching under the DN
<literal>ou=groups,dc=acegisecurity,dc=org</literal> with the default
filter <literal>(member=&lt;user's-DN&gt;)</literal>. The role name
will be taken from the <quote>ou</quote> attribute of each
match.</para>
<para>We've also included the configuration for a user search object,
which uses the filter
<literal>(uid=&lt;user-login-name&gt;)</literal>. This could be used
instead of the DN-pattern (or in addition to it), by setting the
authenticator's <property>userSearch</property> property. The
authenticator would then call the search object to obtain the correct
user's DN before attempting to bind as this user.</para>
</sect1>
</chapter>
<chapter id="cas">
<title>CAS Authentication</title>
<sect1 id="cas-overview">
<title>Overview</title>
<para>JA-SIG produces an enterprise-wide single sign on system known
as CAS. Unlike other initiatives, JA-SIG's Central Authentication
Service is open source, widely used, simple to understand, platform
independent, and supports proxy capabilities. Acegi Security fully
supports CAS, and provides an easy migration path from
single-application deployments of Acegi Security through to
multiple-application deployments secured by an enterprise-wide CAS
server.</para>
<para>You can learn more about CAS at
<literal>http://www.ja-sig.org/products/cas/</literal>. You will need
to visit this URL to download the CAS Server files. Whilst Acegi
Security includes two CAS libraries in the "-with-dependencies" ZIP
file, you will still need the CAS Java Server Pages and
<literal>web.xml</literal> to customise and deploy your CAS
server.</para>
</sect1>
<sect1 id="cas-how-it-works">
<title>How CAS Works</title>
<para>Whilst the CAS web site above contains two documents that detail
the architecture of CAS, we present the general overview again here
within the context of Acegi Security. The following refers to both CAS
2.0 (produced by Yale) and CAS 3.0 (produced by JA-SIG), being the
versions of CAS that Acegi Security supports.</para>
<para>Somewhere in your enterprise you will need to setup a CAS
server. The CAS server is simply a standard WAR file, so there isn't
anything difficult about setting up your server. Inside the WAR file
you will customise the login and other single sign on pages displayed
to users.</para>
<para>If you are deploying CAS 2.0, you will also need to specify in
the web.xml a <literal>PasswordHandler</literal>. The
<literal>PasswordHandler</literal> has a simple method that returns a
boolean as to whether a given username and password is valid. Your
<literal>PasswordHandler</literal> implementation will need to link
into some type of backend authentication repository, such as an LDAP
server or database.</para>
<para>If you are already running an existing CAS 2.0 server instance,
you will have already established a
<literal>PasswordHandler</literal>. If you do not already have a
<literal>PasswordHandler</literal>, you might prefer to use Acegi
Security <literal>CasPasswordHandler</literal> class. This class
delegates through to the standard Acegi Security
<literal>AuthenticationManager</literal>, enabling you to use a
security configuration you might already have in place. You do not
need to use the <literal>CasPasswordHandler</literal> class on your
CAS server if you do not wish. Acegi Security will function as a CAS
client successfully irrespective of the
<literal>PasswordHandler</literal> you've chosen for your CAS
server.</para>
<para>If you are deploying CAS 3.0, you will also need to specify an
<literal>AuthenticationHandler</literal> in the
deployerConfigContext.xml included with CAS. The
<literal>AuthenticationHandler</literal> has a simple method that
returns a boolean as to whether a given set of Credentials is valid.
Your <literal>AuthenticationHandler</literal> implementation will need
to link into some type of backend authentication repository, such as
an LDAP server or database. CAS itself includes numerous
<literal>AuthenticationHandler</literal>s out of the box to assist
with this.</para>
<para>If you are already running an existing CAS 3.0 server instance,
you will have already established an
<literal>AuthenticationHandler</literal>. If you do not already have
an <literal>AuthenticationHandler</literal>, you might prefer to use
Acegi Security <literal>CasAuthenticationHandler</literal> class. This
class delegates through to the standard Acegi Security
<literal>AuthenticationManager</literal>, enabling you to use a
security configuration you might already have in place. You do not
need to use the <literal>CasAuthenticationHandler</literal> class on
your CAS server if you do not wish. Acegi Security will function as a
CAS client successfully irrespective of the
<literal>AuthenticationHandler</literal> you've chosen for your CAS
server.</para>
<para>Apart from the CAS server itself, the other key player is of
course the secure web applications deployed throughout your
enterprise. These web applications are known as "services". There are
two types of services: standard services and proxy services. A proxy
service is able to request resources from other services on behalf of
the user. This will be explained more fully later.</para>
<para>Services can be developed in a large variety of languages, due
to CAS 2.0's very light XML-based protocol. The JA-SIG CAS home page
contains a clients archive which demonstrates CAS clients in Java,
Active Server Pages, Perl, Python and others. Naturally, Java support
is very strong given the CAS server is written in Java. You do not
need to use any of CAS' client classes in applications secured by
Acegi Security. This is handled transparently for you.</para>
<para>The basic interaction between a web browser, CAS server and an
Acegi Security for System Spring secured service is as follows:</para>
<orderedlist>
<listitem>
<para>The web user is browsing the service's public pages. CAS or
Acegi Security is not involved.</para>
</listitem>
<listitem>
<para>The user eventually requests a page that is either secure or
one of the beans it uses is secure. Acegi Security's
<literal>ExceptionTranslationFilter</literal> will detect the
<literal>AuthenticationException</literal>.</para>
</listitem>
<listitem>
<para>Because the user's <literal>Authentication</literal> object
(or lack thereof) caused an
<literal>AuthenticationException</literal>, the
<literal>ExceptionTranslationFilter</literal> will call the
configured <literal>AuthenticationEntryPoint</literal>. If using
CAS, this will be the
<literal>CasProcessingFilterEntryPoint</literal> class.</para>
</listitem>
<listitem>
<para>The <literal>CasProcessingFilterEntry</literal> point will
redirect the user's browser to the CAS server. It will also
indicate a <literal>service</literal> parameter, which is the
callback URL for Acegi Security service. For example, the URL to
which the browser is redirected might be
<literal>https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_acegi_cas_security_check</literal>.</para>
</listitem>
<listitem>
<para>After the user's browser redirects to CAS, they will be
prompted for their username and password. If the user presents a
session cookie which indicates they've previously logged on, they
will not be prompted to login again (there is an exception to this
procedure, which we'll cover later). CAS will use the
<literal>PasswordHandler</literal> (or
<literal>AuthenticationHandler</literal> if using CAS 3.0)
discussed above to decide whether the username and password is
valid.</para>
</listitem>
<listitem>
<para>Upon successful login, CAS will redirect the user's browser
back to the original service. It will also include a
<literal>ticket</literal> parameter, which is an opaque string
representing the "service ticket". Continuing our earlier example,
the URL the browser is redirected to might be
<literal>https://server3.company.com/webapp/j_acegi_cas_security_check?ticket=ST-0-ER94xMJmn6pha35CQRoZ</literal>.</para>
</listitem>
<listitem>
<para>Back in the service web application, the
<literal>CasProcessingFilter</literal> is always listening for
requests to <literal>/j_acegi_cas_security_check</literal> (this
is configurable, but we'll use the defaults in this introduction).
The processing filter will construct a
<literal>UsernamePasswordAuthenticationToken</literal>
representing the service ticket. The principal will be equal to
<literal>CasProcessingFilter.CAS_STATEFUL_IDENTIFIER</literal>,
whilst the credentials will be the service ticket opaque value.
This authentication request will then be handed to the configured
<literal>AuthenticationManager</literal>.</para>
</listitem>
<listitem>
<para>The <literal>AuthenticationManager</literal> implementation
will be the <literal>ProviderManager</literal>, which is in turn
configured with the <literal>CasAuthenticationProvider</literal>.
The <literal>CasAuthenticationProvider</literal> only responds to
<literal>UsernamePasswordAuthenticationToken</literal>s containing
the CAS-specific principal (such as
<literal>CasProcessingFilter.CAS_STATEFUL_IDENTIFIER</literal>)
and <literal>CasAuthenticationToken</literal>s (discussed
later).</para>
</listitem>
<listitem>
<para><literal>CasAuthenticationProvider</literal> will validate
the service ticket using a <literal>TicketValidator</literal>
implementation. Acegi Security includes one implementation, the
<literal>CasProxyTicketValidator</literal>. This implementation a
ticket validation class included in the CAS client library. The
<literal>CasProxyTicketValidator</literal> makes a HTTPS request
to the CAS server in order to validate the service ticket. The
<literal>CasProxyTicketValidator</literal> may also include a
proxy callback URL, which is included in this example:
<literal>https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_acegi_cas_security_check&amp;ticket=ST-0-ER94xMJmn6pha35CQRoZ&amp;pgtUrl=https://server3.company.com/webapp/casProxy/receptor</literal>.</para>
</listitem>
<listitem>
<para>Back on the CAS server, the proxy validation request will be
received. If the presented service ticket matches the service URL
the ticket was issued to, CAS will provide an affirmative response
in XML indicating the username. If any proxy was involved in the
authentication (discussed below), the list of proxies is also
included in the XML response.</para>
</listitem>
<listitem>
<para>[OPTIONAL] If the request to the CAS validation service
included the proxy callback URL (in the <literal>pgtUrl</literal>
parameter), CAS will include a <literal>pgtIou</literal> string in
the XML response. This <literal>pgtIou</literal> represents a
proxy-granting ticket IOU. The CAS server will then create its own
HTTPS connection back to the <literal>pgtUrl</literal>. This is to
mutually authenticate the CAS server and the claimed service URL.
The HTTPS connection will be used to send a proxy granting ticket
to the original web application. For example,
<literal>https://server3.company.com/webapp/casProxy/receptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&amp;pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH</literal>.
We suggest you use CAS' <literal>ProxyTicketReceptor</literal>
servlet to receive these proxy-granting tickets, if they are
required.</para>
</listitem>
<listitem>
<para>The <literal>CasProxyTicketValidator</literal> will parse
the XML received from the CAS server. It will return to the
<literal>CasAuthenticationProvider</literal> a
<literal>TicketResponse</literal>, which includes the username
(mandatory), proxy list (if any were involved), and proxy-granting
ticket IOU (if the proxy callback was requested).</para>
</listitem>
<listitem>
<para>Next <literal>CasAuthenticationProvider</literal> will call
a configured <literal>CasProxyDecider</literal>. The
<literal>CasProxyDecider</literal> indicates whether the proxy
list in the <literal>TicketResponse</literal> is acceptable to the
service. Several implementations are provided with Acegi Security
System: <literal>RejectProxyTickets</literal>,
<literal>AcceptAnyCasProxy</literal> and
<literal>NamedCasProxyDecider</literal>. These names are largely
self-explanatory, except <literal>NamedCasProxyDecider</literal>
which allows a <literal>List</literal> of trusted proxies to be
provided.</para>
</listitem>
<listitem>
<para><literal>CasAuthenticationProvider</literal> will next
request a <literal>CasAuthoritiesPopulator</literal> to advise the
<literal>GrantedAuthority</literal> objects that apply to the user
contained in the <literal>TicketResponse</literal>. Acegi Security
includes a <literal>DaoCasAuthoritiesPopulator</literal> which
simply uses the <literal>UserDetailsService</literal>
infrastructure to find the <literal>UserDetails</literal> and
their associated <literal>GrantedAuthority</literal>s. Note that
the password and enabled/disabled status of
<literal>UserDetails</literal> returned by the
<literal>UserDetailsService</literal> are ignored, as the CAS
server is responsible for authentication decisions.
<literal>DaoCasAuthoritiesPopulator</literal> is only concerned
with retrieving the <literal>GrantedAuthority</literal>s.</para>
</listitem>
<listitem>
<para>If there were no problems,
<literal>CasAuthenticationProvider</literal> constructs a
<literal>CasAuthenticationToken</literal> including the details
contained in the <literal>TicketResponse</literal> and the
<literal>GrantedAuthority</literal>s. The
<literal>CasAuthenticationToken</literal> contains the hash of a
key, so that the <literal>CasAuthenticationProvider</literal>
knows it created it.</para>
</listitem>
<listitem>
<para>Control then returns to
<literal>CasProcessingFilter</literal>, which places the created
<literal>CasAuthenticationToken</literal> into the
<literal>HttpSession</literal> attribute named
<literal>HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY</literal>.</para>
</listitem>
<listitem>
<para>The user's browser is redirected to the original page that
caused the <literal>AuthenticationException</literal>.</para>
</listitem>
<listitem>
<para>As the <literal>Authentication</literal> object is now in
the well-known location, it is handled like any other
authentication approach. Usually the
<literal>HttpSessionIntegrationFilter</literal> will be used to
associate the <literal>Authentication</literal> object with the
<literal>SecurityContextHolder</literal> for the duration of each
request.</para>
</listitem>
</orderedlist>
<para>It's good that you're still here! It might sound involved, but
you can relax as Acegi Security classes hide much of the complexity.
Let's now look at how this is configured</para>
</sect1>
<sect1 id="cas-server">
<title>Optional CAS Server Setup</title>
<para>Acegi Security can even act as the backend which a CAS version
2.0 or 3.0 server utilises. The configuration approach is described
below. Of course, if you have an existing CAS environment you might
just like to use it instead.</para>
<sect2 id="cas-server-2">
<title>CAS Version 2.0</title>
<para>As mentioned above, Acegi Security includes a
<literal>PasswordHandler</literal> that bridges your existing
<literal>AuthenticationManager</literal> into CAS 2.0. You do not
need to use this <literal>PasswordHandler</literal> to use Acegi
Security on the client side (any CAS
<literal>PasswordHandler</literal> will do).</para>
<para>To install, you will need to download and extract the CAS
server archive. We used version 2.0.12. There will be a
<literal>/web</literal> directory in the root of the deployment.
Copy an <literal>applicationContext.xml</literal> containing your
<literal>AuthenticationManager</literal> as well as the
<literal>CasPasswordHandler</literal> into the
<literal>/web/WEB-INF</literal> directory. A sample
<literal>applicationContext.xml</literal> is included below:</para>
<programlisting>
&lt;bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"&gt;
&lt;property name="userMap"&gt;
&lt;value&gt;
marissa=koala,ROLES_IGNORED_BY_CAS
dianne=emu,ROLES_IGNORED_BY_CAS
scott=wombat,ROLES_IGNORED_BY_CAS
peter=opal,disabled,ROLES_IGNORED_BY_CAS
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;
&lt;property name="userDetailsService"&gt;&lt;ref bean="inMemoryDaoImpl"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt;
&lt;property name="providers"&gt;
&lt;list&gt;
&lt;ref bean="daoAuthenticationProvider"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="casPasswordHandler" class="org.acegisecurity.adapters.cas.CasPasswordHandler"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting>
<para>Note the granted authorities are ignored by CAS because it has
no way of communicating the granted authorities to calling
applications. CAS is only concerned with username and passwords (and
the enabled/disabled status).</para>
<para>Next you will need to edit the existing
<literal>/web/WEB-INF/web.xml</literal> file. Add (or edit in the
case of the <literal>authHandler</literal> property) the following
lines:</para>
<para><programlisting>
&lt;context-param&gt;
&lt;param-name&gt;edu.yale.its.tp.cas.authHandler&lt;/param-name&gt;
&lt;param-value&gt;org.acegisecurity.adapters.cas.CasPasswordHandlerProxy&lt;/param-value&gt;
&lt;/context-param&gt;
&lt;context-param&gt;
&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;
&lt;/context-param&gt;
&lt;listener&gt;
&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
&lt;/listener&gt;
</programlisting></para>
<para>Copy the <literal>spring.jar</literal> and
<literal>acegi-security.jar</literal> files into
<literal>/web/WEB-INF/lib</literal>. Now use the <literal>ant
dist</literal> task in the <literal>build.xml</literal> in the root
of the directory structure. This will create
<literal>/lib/cas.war</literal>, which is ready for deployment to
your servlet container.</para>
<para>Note CAS heavily relies on HTTPS. You can't even test the
system without a HTTPS certificate. Whilst you should refer to your
web container's documentation on setting up HTTPS, if you need some
additional help or a test certificate you might like to check the
<literal>samples/contacts/etc/ssl</literal> directory</para>
</sect2>
<sect2 id="cas-server-3">
<title>CAS Version 3.0</title>
<para>As mentioned above, Acegi Security includes an
<literal>AuthenticationHandler</literal> that bridges your existing
<literal>AuthenticationManager</literal> into CAS 3.0. You do not
need to use this <literal>AuthenticationHandler</literal> to use
Acegi Security on the client side (any CAS
<literal>AuthenticationHandler</literal> will do).</para>
<para>To install, you will need to download and extract the CAS
server archive. We used version 3.0.4. There will be a
<literal>/webapp</literal> directory in the root of the deployment.
Edit the an <literal>deployerConfigContext.xml</literal> so that it
contains your <literal>AuthenticationManager</literal> as well as
the <literal>CasAuthenticationHandler</literal>. A sample
<literal>applicationContext.xml</literal> is included below:</para>
<programlisting>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"&gt;
&lt;beans&gt;
&lt;bean
id="authenticationManager"
class="org.jasig.cas.authentication.AuthenticationManagerImpl"&gt;
&lt;property name="credentialsToPrincipalResolvers"&gt;
&lt;list&gt;
&lt;bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" /&gt;
&lt;bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" /&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="authenticationHandlers"&gt;
&lt;list&gt;
&lt;bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" /&gt;
&lt;bean class="org.acegisecurity.adapters.cas3.CasAuthenticationHandler"&gt;
&lt;property name="authenticationManager" ref="acegiAuthenticationManager" /&gt;
&lt;/bean&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"&gt;
&lt;property name="userMap"&gt;
&lt;value&gt;
marissa=koala,ROLES_IGNORED_BY_CAS
dianne=emu,ROLES_IGNORED_BY_CAS
scott=wombat,ROLES_IGNORED_BY_CAS
peter=opal,disabled,ROLES_IGNORED_BY_CAS
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;
&lt;property name="userDetailsService"&gt;&lt;ref bean="inMemoryDaoImpl"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="acegiAuthenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt;
&lt;property name="providers"&gt;
&lt;list&gt;
&lt;ref bean="daoAuthenticationProvider"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;/beans&gt;
</programlisting>
<para>Note the granted authorities are ignored by CAS because it has
no way of communicating the granted authorities to calling
applications. CAS is only concerned with username and passwords (and
the enabled/disabled status).</para>
<para>Copy Acegi<literal>-security.jar</literal> file into
<literal>/localPlugins/lib</literal>. Now use the <literal>ant
war</literal> task in the <literal>build.xml</literal> in the
/localPlugins directory. This will create
<literal>/localPlugins/target/cas.war</literal>, which is ready for
deployment to your servlet container.</para>
<para>Note CAS heavily relies on HTTPS. You can't even test the
system without a HTTPS certificate. Whilst you should refer to your
web container's documentation on setting up HTTPS, if you need some
additional help or a test certificate you might like to check the
CAS documentation on setting up SSL:
<literal>http://www.ja-sig.org/products/cas/server/ssl/index.html</literal></para>
</sect2>
</sect1>
<sect1 id="cas-client">
<title>Configuration of CAS Client</title>
<para>The web application side of CAS is made easy due to Acegi
Security. It is assumed you already know the basics of using Acegi
Security, so these are not covered again below. Only the CAS-specific
beans are mentioned.</para>
<para>You will need to add a <literal>ServiceProperties</literal> bean
to your application context. This represents your service:</para>
<para><programlisting>
&lt;bean id="serviceProperties" class="org.acegisecurity.ui.cas.ServiceProperties"&gt;
&lt;property name="service"&gt;&lt;value&gt;https://localhost:8443/contacts-cas/j_acegi_cas_security_check&lt;/value&gt;&lt;/property&gt;
&lt;property name="sendRenew"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting></para>
<para>The <literal>service</literal> must equal a URL that will be
monitored by the <literal>CasProcessingFilter</literal>. The
<literal>sendRenew</literal> defaults to false, but should be set to
true if your application is particularly sensitive. What this
parameter does is tell the CAS login service that a single sign on
login is unacceptable. Instead, the user will need to re-enter their
username and password in order to gain access to the service.</para>
<para>The following beans should be configured to commence the CAS
authentication process:</para>
<para><programlisting>
&lt;bean id="casProcessingFilter" class="org.acegisecurity.ui.cas.CasProcessingFilter"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="authenticationFailureUrl"&gt;&lt;value&gt;/casfailed.jsp&lt;/value&gt;&lt;/property&gt;
&lt;property name="defaultTargetUrl"&gt;&lt;value&gt;/&lt;/value&gt;&lt;/property&gt;
&lt;property name="filterProcessesUrl"&gt;&lt;value&gt;/j_acegi_cas_security_check&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"&gt;
&lt;property name="authenticationEntryPoint"&gt;&lt;ref local="casProcessingFilterEntryPoint"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="casProcessingFilterEntryPoint" class="org.acegisecurity.ui.cas.CasProcessingFilterEntryPoint"&gt;
&lt;property name="loginUrl"&gt;&lt;value&gt;https://localhost:8443/cas/login&lt;/value&gt;&lt;/property&gt;
&lt;property name="serviceProperties"&gt;&lt;ref bean="serviceProperties"/&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting></para>
<para>You will also need to add the
<literal>CasProcessingFilter</literal> to web.xml:</para>
<para><programlisting>
&lt;filter&gt;
&lt;filter-name&gt;Acegi CAS Processing Filter&lt;/filter-name&gt;
&lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;targetClass&lt;/param-name&gt;
&lt;param-value&gt;org.acegisecurity.ui.cas.CasProcessingFilter&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;Acegi CAS Processing Filter&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;
</programlisting></para>
<para>The <literal>CasProcessingFilter</literal> has very similar
properties to the <literal>AuthenticationProcessingFilter</literal>
(used for form-based logins). Each property is
self-explanatory.</para>
<para>For CAS to operate, the
<literal>ExceptionTranslationFilter</literal> must have its
<literal>authenticationEntryPoint</literal> property set to the
<literal>CasProcessingFilterEntryPoint</literal> bean.</para>
<para>The <literal>CasProcessingFilterEntryPoint</literal> must refer
to the <literal>ServiceProperties</literal> bean (discussed above),
which provides the URL to the enterprise's CAS login server. This is
where the user's browser will be redirected.</para>
<para>Next you need to add an <literal>AuthenticationManager</literal>
that uses <literal>CasAuthenticationProvider</literal> and its
collaborators:</para>
<para><programlisting>
&lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"&gt;
&lt;property name="providers"&gt;
&lt;list&gt;
&lt;ref bean="casAuthenticationProvider"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="casAuthenticationProvider" class="org.acegisecurity.providers.cas.CasAuthenticationProvider"&gt;
&lt;property name="casAuthoritiesPopulator"&gt;&lt;ref bean="casAuthoritiesPopulator"/&gt;&lt;/property&gt;
&lt;property name="casProxyDecider"&gt;&lt;ref bean="casProxyDecider"/&gt;&lt;/property&gt;
&lt;property name="ticketValidator"&gt;&lt;ref bean="casProxyTicketValidator"/&gt;&lt;/property&gt;
&lt;property name="statelessTicketCache"&gt;&lt;ref bean="statelessTicketCache"/&gt;&lt;/property&gt;
&lt;property name="key"&gt;&lt;value&gt;my_password_for_this_auth_provider_only&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="casProxyTicketValidator" class="org.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator"&gt;
&lt;property name="casValidate"&gt;&lt;value&gt;https://localhost:8443/cas/proxyValidate&lt;/value&gt;&lt;/property&gt;
&lt;property name="proxyCallbackUrl"&gt;&lt;value&gt;https://localhost:8443/contacts-cas/casProxy/receptor&lt;/value&gt;&lt;/property&gt;
&lt;property name="serviceProperties"&gt;&lt;ref bean="serviceProperties"/&gt;&lt;/property&gt;
&lt;!-- &lt;property name="trustStore"&gt;&lt;value&gt;/some/path/to/your/lib/security/cacerts&lt;/value&gt;&lt;/property&gt; --&gt;
&lt;/bean&gt;
&lt;bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&gt;
&lt;property name="configLocation"&gt;
&lt;value&gt;classpath:/ehcache-failsafe.xml&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="ticketCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&gt;
&lt;property name="cacheManager"&gt;
&lt;ref local="cacheManager"/&gt;
&lt;/property&gt;
&lt;property name="cacheName"&gt;
&lt;value&gt;ticketCache&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="statelessTicketCache" class="org.acegisecurity.providers.cas.cache.EhCacheBasedTicketCache"&gt;
&lt;property name="cache"&gt;&lt;ref local="ticketCacheBackend"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="casAuthoritiesPopulator" class="org.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator"&gt;
&lt;property name="userDetailsService"&gt;&lt;ref bean="inMemoryDaoImpl"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="casProxyDecider" class="org.acegisecurity.providers.cas.proxy.RejectProxyTickets"/&gt;
</programlisting></para>
<para>The beans are all reasonable self-explanatory if you refer back
to the "How CAS Works" section. Careful readers might notice one
surprise: the <literal>statelessTicketCache</literal> property of the
<literal>CasAuthenticationProvider</literal>. This is discussed in
detail in the "Advanced CAS Usage" section.</para>
<para>Note the <literal>CasProxyTicketValidator</literal> has a
remarked out <literal>trustStore</literal> property. This property
might be helpful if you experience HTTPS certificate issues. Also note
the <literal>proxyCallbackUrl</literal> is set so the service can
receive a proxy-granting ticket. As mentioned above, this is optional
and unnecessary if you do not require proxy-granting tickets. If you
do use this feature, you will need to configure a suitable servlet to
receive the proxy-granting tickets. We suggest you use CAS'
<literal>ProxyTicketReceptor</literal> by adding the following to your
web application's <literal>web.xml</literal>:</para>
<para><programlisting>
&lt;servlet&gt;
&lt;servlet-name&gt;casproxy&lt;/servlet-name&gt;
&lt;servlet-class&gt;edu.yale.its.tp.cas.proxy.ProxyTicketReceptor&lt;/servlet-class&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;casproxy&lt;/servlet-name&gt;
&lt;url-pattern&gt;/casProxy/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
</programlisting></para>
<para>This completes the configuration of CAS. If you haven't made any
mistakes, your web application should happily work within the
framework of CAS single sign on. No other parts of Acegi Security need
to be concerned about the fact CAS handled authentication.</para>
<para>There is also a <literal>contacts-cas.war</literal> file in the
sample applications directory. This sample application uses the above
settings and can be deployed to see CAS in operation</para>
</sect1>
<sect1 id="cas-advanced">
<title>Advanced Issues</title>
<para>The <literal>CasAuthenticationProvider</literal> distinguishes
between stateful and stateless clients. A stateful client is
considered any that originates via the
<literal>CasProcessingFilter</literal>. A stateless client is any that
presents an authentication request via the
<literal>UsernamePasswordAuthenticationToken</literal> with a
principal equal to
<literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>.</para>
<para>Stateless clients are likely to be via remoting protocols such
as Hessian and Burlap. The <literal>BasicProcessingFilter</literal> is
still used in this case, but the remoting protocol client is expected
to present a username equal to the static string above, and a password
equal to a CAS service ticket. Clients should acquire a CAS service
ticket directly from the CAS server.</para>
<para>Because remoting protocols have no way of presenting themselves
within the context of a <literal>HttpSession</literal>, it isn't
possible to rely on the <literal>HttpSession</literal>'s
<literal>HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY</literal>
attribute to locate the <literal>CasAuthenticationToken</literal>.
Furthermore, because the CAS server invalidates a service ticket after
it has been validated by the <literal>TicketValidator</literal>,
presenting the same service ticket on subsequent requests will not
work. It is similarly very difficult to obtain a proxy-granting ticket
for a remoting protocol client, as they are often deployed on client
machines which rarely have HTTPS URLs that would be accessible to the
CAS server.</para>
<para>One obvious option is to not use CAS at all for remoting
protocol clients. However, this would eliminate many of the desirable
features of CAS.</para>
<para>As a middle-ground, the
<literal>CasAuthenticationProvider</literal> uses a
<literal>StatelessTicketCache</literal>. This is used solely for
requests with a principal equal to
<literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>. What
happens is the <literal>CasAuthenticationProvider</literal> will store
the resulting <literal>CasAuthenticationToken</literal> in the
<literal>StatelessTicketCache</literal>, keyed on the service ticket.
Accordingly, remoting protocol clients can present the same service
ticket and the <literal>CasAuthenticationProvider</literal> will not
need to contact the CAS server for validation (aside from the first
request).</para>
<para>The other aspect of advanced CAS usage involves creating proxy
tickets from the proxy-granting ticket. As indicated above, we
recommend you use CAS' <literal>ProxyTicketReceptor</literal> to
receive these tickets. The <literal>ProxyTicketReceptor</literal>
provides a static method that enables you to obtain a proxy ticket by
presenting the proxy-granting IOU ticket. You can obtain the
proxy-granting IOU ticket by calling
<literal>CasAuthenticationToken.getProxyGrantingTicketIou()</literal>.</para>
<para>It is hoped you find CAS integration easy and useful with Acegi
Security classes. Welcome to enterprise-wide single sign on!</para>
</sect1>
</chapter>
<chapter id="ca">
<title>Container Adapter Authentication</title>
<sect1 id="ca-overview">
<title>Overview</title>
<para>Very early versions of Acegi 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.</para>
<para>Container Adapters enable Acegi 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 <literal>isUserInRole()</literal> and form-based or basic
authentication), whilst benefiting from the enhanced security
interception capabilities provided by Acegi Security (it should be
noted that Acegi Security also offers
<literal>ContextHolderAwareRequestWrapper</literal> to deliver
<literal>isUserInRole()</literal> and similar Servlet Specification
compatibility methods).</para>
<para>The integration between a container and Acegi Security is
achieved through an adapter. The adapter provides a
container-compatible user authentication provider, and needs to return
a container-compatible user object.</para>
<para>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
<literal>acegisecurity.xml</literal> and is placed in a
container-specific location.</para>
<para>Acegi Security currently supports Jetty, Catalina (Tomcat),
JBoss and Resin. Additional container adapters can easily be
written</para>
</sect1>
<sect1 id="ca-adapter">
<title>Adapter Authentication Provider</title>
<para>As is always the case, the container adapter generated
<literal>Authentication</literal> object still needs to be
authenticated by an <literal>AuthenticationManager</literal> when
requested to do so by the
<literal>AbstractSecurityInterceptor</literal>. The
<literal>AuthenticationManager</literal> needs to be certain the
adapter-provided <literal>Authentication</literal> object is valid and
was actually authenticated by a trusted adapter.</para>
<para>Adapters create <literal>Authentication</literal> objects which
are immutable and implement the <literal>AuthByAdapter</literal>
interface. These objects store the hash of a key that is defined by
the adapter. This allows the <literal>Authentication</literal> object
to be validated by the <literal>AuthByAdapterProvider</literal>. This
authentication provider is defined as follows:</para>
<para><programlisting>&lt;bean id="authByAdapterProvider" class="org.acegisecurity.adapters.AuthByAdapterProvider"&gt;
&lt;property name="key"&gt;&lt;value&gt;my_password&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>The key must match the key that is defined in the
container-specific configuration file that starts the adapter. The
<literal>AuthByAdapterProvider</literal> automatically accepts as
valid any <literal>AuthByAdapter</literal> implementation that returns
the expected hash of the key.</para>
<para>To reiterate, this means the adapter will perform the initial
authentication using providers such as
<literal>DaoAuthenticationProvider</literal>, returning an
<literal>AuthByAdapter</literal> instance that contains a hash code of
the key. Later, when an application calls a security interceptor
managed resource, the <literal>AuthByAdapter</literal> instance in the
<literal>SecurityContext</literal> in the
<literal>SecurityContextHolder</literal> will be tested by the
application's <literal>AuthByAdapterProvider</literal>. There is no
requirement for additional authentication providers such as
<literal>DaoAuthenticationProvider</literal> within the
application-specific application context, as the only type of
<literal>Authentication</literal> instance that will be presented by
the application is from the container adapter.</para>
<para>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.</para>
<para>When using container adapters with the
<literal>DaoAuthenticationProvider</literal>, ensure you set its
<literal>forcePrincipalAsString</literal> property to
<literal>true</literal>.</para>
</sect1>
<sect1 id="ca-jetty">
<title>Jetty</title>
<para>The following was tested with Jetty 4.2.18.</para>
<para><literal>$JETTY_HOME</literal> refers to the root of your Jetty
installation.</para>
<para>Edit your <literal>$JETTY_HOME/etc/jetty.xml</literal> file so
the <literal>&lt;Configure class&gt;</literal> section has a new
<literal>addRealm</literal> call:</para>
<para><programlisting>
&lt;Call name="addRealm"&gt;
&lt;Arg&gt;
&lt;New class="org.acegisecurity.adapters.jetty.JettyAcegiUserRealm"&gt;
&lt;Arg&gt;Spring Powered Realm&lt;/Arg&gt;
&lt;Arg&gt;my_password&lt;/Arg&gt;
&lt;Arg&gt;etc/acegisecurity.xml&lt;/Arg&gt;
&lt;/New&gt;
&lt;/Arg&gt;
&lt;/Call&gt;
</programlisting></para>
<para>Copy <literal>acegisecurity.xml</literal> into
<literal>$JETTY_HOME/etc</literal>.</para>
<para>Copy the following files into
<literal>$JETTY_HOME/ext</literal>:<itemizedlist>
<listitem>
<para><literal>aopalliance.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-logging.jar</literal></para>
</listitem>
<listitem>
<para><literal>spring.jar</literal></para>
</listitem>
<listitem>
<para><literal>acegi-security-jetty-XX.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-codec.jar</literal></para>
</listitem>
<listitem>
<para><literal>burlap.jar</literal></para>
</listitem>
<listitem>
<para><literal>hessian.jar</literal></para>
</listitem>
</itemizedlist></para>
<para>None of the above JAR files (or
<literal>acegi-security-XX.jar</literal>) should be in your
application's <literal>WEB-INF/lib</literal>. The realm name indicated
in your <literal>web.xml</literal> does matter with Jetty. The
<literal>web.xml</literal> must express the same
<literal>&lt;realm-name&gt;</literal> as your
<literal>jetty.xml</literal> (in the example above, "Spring Powered
Realm").</para>
</sect1>
<sect1 id="ca-jboss">
<title>JBoss</title>
<para>The following was tested with JBoss 3.2.6.</para>
<para><literal>$JBOSS_HOME</literal> refers to the root of your JBoss
installation.</para>
<para>There are two different ways of making spring context available
to the Jboss integration classes.</para>
<para>The first approach is by editing your
<literal>$JBOSS_HOME/server/your_config/conf/login-config.xml</literal>
file so that it contains a new entry under the
<literal>&lt;Policy&gt;</literal> section:</para>
<para><programlisting>
&lt;application-policy name = "SpringPoweredRealm"&gt;
&lt;authentication&gt;
&lt;login-module code = "org.acegisecurity.adapters.jboss.JbossAcegiLoginModule"
flag = "required"&gt;
&lt;module-option name = "appContextLocation"&gt;acegisecurity.xml&lt;/module-option&gt;
&lt;module-option name = "key"&gt;my_password&lt;/module-option&gt;
&lt;/login-module&gt;
&lt;/authentication&gt;
&lt;/application-policy&gt;
</programlisting></para>
<para>Copy <literal>acegisecurity.xml</literal> into
<literal>$JBOSS_HOME/server/your_config/conf</literal>.</para>
<para>In this configuration <literal>acegisecurity.xml</literal>
contains the spring context definition including all the
authentication manager beans. You have to bear in mind though, that
<literal>SecurityContext</literal> 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
<literal>org.springframework.beans.factory.access.SingletonBeanFactoryLocator</literal>.
The required configuration for this approach is:</para>
<para><programlisting>
&lt;application-policy name = "SpringPoweredRealm"&gt;
&lt;authentication&gt;
&lt;login-module code = "org.acegisecurity.adapters.jboss.JbossAcegiLoginModule"
flag = "required"&gt;
&lt;module-option name = "singletonId"&gt;springRealm&lt;/module-option&gt;
&lt;module-option name = "key"&gt;my_password&lt;/module-option&gt;
&lt;module-option name = "authenticationManager"&gt;authenticationManager&lt;/module-option&gt;
&lt;/login-module&gt;
&lt;/authentication&gt;
&lt;/application-policy&gt;
</programlisting></para>
<para>In the above code fragment,
<literal>authenticationManager</literal> is a helper property that
defines the expected name of the
<literal>AuthenticationManager</literal> in case you have several
defined in the IoC container. The <literal>singletonId</literal>
property references a bean defined in a
<literal>beanRefFactory.xml</literal> file. This file needs to be
available from anywhere on the JBoss classpath, including
<literal>$JBOSS_HOME/server/your_config/conf</literal>. The
<literal>beanRefFactory.xml</literal> contains the following
declaration:</para>
<para><programlisting>
&lt;beans&gt;
&lt;bean id="springRealm" singleton="true" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"&gt;
&lt;constructor-arg&gt;
&lt;list&gt;
&lt;value&gt;acegisecurity.xml&lt;/value&gt;
&lt;/list&gt;
&lt;/constructor-arg&gt;
&lt;/bean&gt;
&lt;/beans&gt;
</programlisting></para>
<para>Finally, irrespective of the configuration approach you need to
copy the following files into
<literal>$JBOSS_HOME/server/your_config/lib</literal>:<itemizedlist>
<listitem>
<para><literal>aopalliance.jar</literal></para>
</listitem>
<listitem>
<para><literal>spring.jar</literal></para>
</listitem>
<listitem>
<para><literal>acegi-security-jboss-XX.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-codec.jar</literal></para>
</listitem>
<listitem>
<para><literal>burlap.jar</literal></para>
</listitem>
<listitem>
<para><literal>hessian.jar</literal></para>
</listitem>
</itemizedlist></para>
<para>None of the above JAR files (or
<literal>acegi-security-XX.jar</literal>) should be in your
application's <literal>WEB-INF/lib</literal>. The realm name indicated
in your <literal>web.xml</literal> does not matter with JBoss.
However, your web application's
<literal>WEB-INF/jboss-web.xml</literal> must express the same
<literal>&lt;security-domain&gt;</literal> as your
<literal>login-config.xml</literal>. For example, to match the above
example, your <literal>jboss-web.xml</literal> would look like
this:</para>
<para><programlisting>
&lt;jboss-web&gt;
&lt;security-domain&gt;java:/jaas/SpringPoweredRealm&lt;/security-domain&gt;
&lt;/jboss-web&gt;</programlisting></para>
<para>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.</para>
</sect1>
<sect1 id="ca-resin">
<title>Resin</title>
<para>The following was tested with Resin 3.0.6.</para>
<para><literal>$RESIN_HOME</literal> refers to the root of your Resin
installation.</para>
<para>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.</para>
<para>Copy the following files into
<literal>$RESIN_HOME/lib</literal>:<itemizedlist>
<listitem>
<para><literal>aopalliance.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-logging.jar</literal></para>
</listitem>
<listitem>
<para><literal>spring.jar</literal></para>
</listitem>
<listitem>
<para><literal>acegi-security-resin-XX.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-codec.jar</literal></para>
</listitem>
<listitem>
<para><literal>burlap.jar</literal></para>
</listitem>
<listitem>
<para><literal>hessian.jar</literal></para>
</listitem>
</itemizedlist></para>
<para>Unlike the container-wide <literal>acegisecurity.xml</literal>
files used by other container adapters, each Resin web application
will contain its own
<literal>WEB-INF/resin-acegisecurity.xml</literal> file. Each web
application will also contain a <literal>resin-web.xml</literal> file
which Resin uses to start the container adapter:</para>
<para><programlisting>
&lt;web-app&gt;
&lt;authenticator&gt;
&lt;type&gt;org.acegisecurity.adapters.resin.ResinAcegiAuthenticator&lt;/type&gt;
&lt;init&gt;
&lt;app-context-location&gt;WEB-INF/resin-acegisecurity.xml&lt;/app-context-location&gt;
&lt;key&gt;my_password&lt;/key&gt;
&lt;/init&gt;
&lt;/authenticator&gt;
&lt;/web-app&gt;
</programlisting></para>
<para>With the basic configuration provided above, none of the JAR
files listed (or <literal>acegi-security-XX.jar</literal>) should be
in your application's <literal>WEB-INF/lib</literal>. The realm name
indicated in your <literal>web.xml</literal> does not matter with
Resin, as the relevant authentication class is indicated by the
<literal>&lt;authenticator&gt;</literal> setting</para>
</sect1>
<sect1 id="ca-tomcat">
<title>Tomcat</title>
<para>The following was tested with Jakarta Tomcat 4.1.30 and
5.0.19.</para>
<para><literal>$CATALINA_HOME</literal> refers to the root of your
Catalina (Tomcat) installation.</para>
<para>Edit your <literal>$CATALINA_HOME/conf/server.xml</literal> file
so the <literal>&lt;Engine&gt;</literal> section contains only one
active <literal>&lt;Realm&gt;</literal> entry. An example realm
entry:</para>
<para><programlisting> &lt;Realm className="org.acegisecurity.adapters.catalina.CatalinaAcegiUserRealm"
appContextLocation="conf/acegisecurity.xml"
key="my_password" /&gt;</programlisting></para>
<para>Be sure to remove any other <literal>&lt;Realm&gt;</literal>
entry from your <literal>&lt;Engine&gt;</literal> section.</para>
<para>Copy <literal>acegisecurity.xml</literal> into
<literal>$CATALINA_HOME/conf</literal>.</para>
<para>Copy <literal>acegi-security-catalina-XX.jar</literal> into
<literal>$CATALINA_HOME/server/lib</literal>.</para>
<para>Copy the following files into
<literal>$CATALINA_HOME/common/lib</literal>:</para>
<itemizedlist>
<listitem>
<para><literal>aopalliance.jar</literal></para>
</listitem>
<listitem>
<para><literal>spring.jar</literal></para>
</listitem>
<listitem>
<para><literal>commons-codec.jar</literal></para>
</listitem>
<listitem>
<para><literal>burlap.jar</literal></para>
</listitem>
<listitem>
<para><literal>hessian.jar</literal></para>
</listitem>
</itemizedlist>
<para>None of the above JAR files (or
<literal>acegi-security-XX.jar</literal>) should be in your
application's <literal>WEB-INF/lib</literal>. The realm name indicated
in your <literal>web.xml</literal> does not matter with
Catalina.</para>
<para>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:</para>
<para><programlisting>#!/bin/sh
export CATALINA_HOME="/Library/Tomcat"
export JAVA_HOME="/Library/Java/Home"
cd /
$CATALINA_HOME/bin/startup.sh</programlisting></para>
<para>Finally, restart Tomcat.</para>
</sect1>
</chapter>
</part>
<part id="authorization">
<title>Authorization</title>
<partintro>
<para>The advanced authorization capabilities within Acegi Security
represent one of the most compelling reasons for its popularity.
Irrespective of how you choose to authenticate - whether using an Acegi
Security-provided mechanism and provider, or integrating with a
container or other non-Acegi Security authentication authority - you
will find the authorization services can be used within your application
in a consistent and simple way.</para>
<para>In this part we'll explore the different
<literal>AbstractSecurityInterceptor</literal> implementations, which
were introduced in Part I. We then move on to explore how to fine-tune
authorization through use of domain access control lists.</para>
</partintro>
<chapter id="authorization-common">
<title>Common Authorization Concepts</title>
<sect1 id="authorities">
<title>Authorities</title>
<para>As briefly mentioned in the Authentication section, all
<literal>Authentication</literal> implementations are required to
store an array of <literal>GrantedAuthority</literal> objects. These
represent the authorities that have been granted to the principal. The
<literal>GrantedAuthority</literal> objects are inserted into the
<literal>Authentication</literal> object by the
<literal>AuthenticationManager</literal> and are later read by
<literal>AccessDecisionManager</literal>s when making authorization
decisions.</para>
<para><literal>GrantedAuthority</literal> is an interface with only
one method:</para>
<para><programlisting>public String getAuthority();</programlisting></para>
<para>This method allows <literal>AccessDecisionManager</literal>s to
obtain a precise <literal>String</literal> representation of the
<literal>GrantedAuthority</literal>. By returning a representation as
a <literal>String</literal>, a <literal>GrantedAuthority</literal> can
be easily "read" by most <literal>AccessDecisionManager</literal>s. If
a <literal>GrantedAuthority</literal> cannot be precisely represented
as a <literal>String</literal>, the
<literal>GrantedAuthority</literal> is considered "complex" and
<literal>getAuthority()</literal> must return
<literal>null</literal>.</para>
<para>An example of a "complex" <literal>GrantedAuthority</literal>
would be an implementation that stores a list of operations and
authority thresholds that apply to different customer account numbers.
Representing this complex <literal>GrantedAuthority</literal> as a
<literal>String</literal> would be quite complex, and as a result the
<literal>getAuthority()</literal> method should return
<literal>null</literal>. This will indicate to any
<literal>AccessDecisionManager</literal> that it will need to
specifically support the <literal>GrantedAuthority</literal>
implementation in order to understand its contents.</para>
<para>Acegi Security includes one concrete
<literal>GrantedAuthority</literal> implementation,
<literal>GrantedAuthorityImpl</literal>. This allows any
user-specified <literal>String</literal> to be converted into a
<literal>GrantedAuthority</literal>. All
<literal>AuthenticationProvider</literal>s included with the security
architecture use <literal>GrantedAuthorityImpl</literal> to populate
the <literal>Authentication</literal> object.</para>
</sect1>
<sect1 id="pre-invocation">
<title>Pre-Invocation Handling</title>
<para>The <literal>AccessDecisionManager</literal> is called by the
<literal>AbstractSecurityInterceptor</literal> and is responsible for
making final access control decisions. The
<literal>AccessDecisionManager</literal> interface contains three
methods:</para>
<para><programlisting>public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config) throws AccessDeniedException;
public boolean supports(ConfigAttribute attribute);
public boolean supports(Class clazz);</programlisting></para>
<para>As can be seen from the first method, the
<literal>AccessDecisionManager</literal> is passed via method
parameters all information that is likely to be of value in assessing
an authorization decision. In particular, passing the secure
<literal>Object</literal> enables those arguments contained in the
actual secure object invocation to be inspected. For example, let's
assume the secure object was a <literal>MethodInvocation</literal>. It
would be easy to query the <literal>MethodInvocation</literal> for any
<literal>Customer</literal> argument, and then implement some sort of
security logic in the <literal>AccessDecisionManager</literal> to
ensure the principal is permitted to operate on that customer.
Implementations are expected to throw an
<literal>AccessDeniedException</literal> if access is denied.</para>
<para>The <literal>supports(ConfigAttribute)</literal> method is
called by the <literal>AbstractSecurityInterceptor</literal> at
startup time to determine if the
<literal>AccessDecisionManager</literal> can process the passed
<literal>ConfigAttribute</literal>. The
<literal>supports(Class)</literal> method is called by a security
interceptor implementation to ensure the configured
<literal>AccessDecisionManager</literal> supports the type of secure
object that the security interceptor will present.</para>
<para>Whilst users can implement their own
<literal>AccessDecisionManager</literal> to control all aspects of
authorization, Acegi Security includes several
<literal>AccessDecisionManager</literal> implementations that are
based on voting. Figure 4 illustrates the relevant classes.</para>
<para><mediaobject>
<imageobject role="html">
<imagedata align="center"
fileref="images/AccessDecisionVoting.gif"
format="GIF" />
</imageobject>
<caption>
<para>Figure 4: Voting Decision Manager</para>
</caption>
</mediaobject></para>
<para>Using this approach, a series of
<literal>AccessDecisionVoter</literal> implementations are polled on
an authorization decision. The
<literal>AccessDecisionManager</literal> then decides whether or not
to throw an <literal>AccessDeniedException</literal> based on its
assessment of the votes.</para>
<para>The <literal>AccessDecisionVoter</literal> interface has three
methods:</para>
<para><programlisting>public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);
public boolean supports(ConfigAttribute attribute);
public boolean supports(Class clazz);</programlisting></para>
<para>Concrete implementations return an <literal>int</literal>, with
possible values being reflected in the
<literal>AccessDecisionVoter</literal> static fields
<literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal>
and <literal>ACCESS_GRANTED</literal>. A voting implementation will
return <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an
authorization decision. If it does have an opinion, it must return
either <literal>ACCESS_DENIED</literal> or
<literal>ACCESS_GRANTED</literal>.</para>
<para>There are three concrete
<literal>AccessDecisionManager</literal>s provided with Acegi Security
that tally the votes. The <literal>ConsensusBased</literal>
implementation will grant or deny access based on the consensus of
non-abstain votes. Properties are provided to control behavior in the
event of an equality of votes or if all votes are abstain. The
<literal>AffirmativeBased</literal> implementation will grant access
if one or more <literal>ACCESS_GRANTED</literal> votes were received
(ie a deny vote will be ignored, provided there was at least one grant
vote). Like the <literal>ConsensusBased</literal> implementation,
there is a parameter that controls the behavior if all voters abstain.
The <literal>UnanimousBased</literal> provider expects unanimous
<literal>ACCESS_GRANTED</literal> votes in order to grant access,
ignoring abstains. It will deny access if there is any
<literal>ACCESS_DENIED</literal> vote. Like the other implementations,
there is a parameter that controls the behaviour if all voters
abstain.</para>
<para>It is possible to implement a custom
<literal>AccessDecisionManager</literal> that tallies votes
differently. For example, votes from a particular
<literal>AccessDecisionVoter</literal> might receive additional
weighting, whilst a deny vote from a particular voter may have a veto
effect.</para>
<para>There are two concrete <literal>AccessDecisionVoter</literal>
implementations provided with Acegi Security. The
<literal>RoleVoter</literal> class will vote if any ConfigAttribute
begins with <literal>ROLE_</literal>. It will vote to grant access if
there is a <literal>GrantedAuthority</literal> which returns a
<literal>String</literal> representation (via the
<literal>getAuthority()</literal> method) exactly equal to one or more
<literal>ConfigAttributes</literal> starting with
<literal>ROLE_</literal>. If there is no exact match of any
<literal>ConfigAttribute</literal> starting with
<literal>ROLE_</literal>, the <literal>RoleVoter</literal> will vote
to deny access. If no <literal>ConfigAttribute</literal> begins with
<literal>ROLE_</literal>, the voter will abstain.
<literal>RoleVoter</literal> is case sensitive on comparisons as well
as the <literal>ROLE_</literal> prefix.</para>
<para><literal>BasicAclEntryVoter</literal> is the other concrete
voter included with Acegi Security. It integrates with Acegi
Security's <literal>AclManager</literal> (discussed later). This voter
is designed to have multiple instances in the same application
context, such as:</para>
<para><programlisting>&lt;bean id="aclContactReadVoter" class="org.acegisecurity.vote.BasicAclEntryVoter"&gt;
&lt;property name="processConfigAttribute"&gt;&lt;value&gt;ACL_CONTACT_READ&lt;/value&gt;&lt;/property&gt;
&lt;property name="processDomainObjectClass"&gt;&lt;value&gt;sample.contact.Contact&lt;/value&gt;&lt;/property&gt;
&lt;property name="aclManager"&gt;&lt;ref local="aclManager"/&gt;&lt;/property&gt;
&lt;property name="requirePermission"&gt;
&lt;list&gt;
&lt;ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/&gt;
&lt;ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="aclContactDeleteVoter" class="org.acegisecurity.vote.BasicAclEntryVoter"&gt;
&lt;property name="processConfigAttribute"&gt;&lt;value&gt;ACL_CONTACT_DELETE&lt;/value&gt;&lt;/property&gt;
&lt;property name="processDomainObjectClass"&gt;&lt;value&gt;sample.contact.Contact&lt;/value&gt;&lt;/property&gt;
&lt;property name="aclManager"&gt;&lt;ref local="aclManager"/&gt;&lt;/property&gt;
&lt;property name="requirePermission"&gt;
&lt;list&gt;
&lt;ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/&gt;
&lt;ref local="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>In the above example, you'd define
<literal>ACL_CONTACT_READ</literal> or
<literal>ACL_CONTACT_DELETE</literal> against some methods on a
<literal>MethodSecurityInterceptor</literal> or
<literal>AspectJSecurityInterceptor</literal>. When those methods are
invoked, the above applicable voter defined above would vote to grant
or deny access. The voter would look at the method invocation to
locate the first argument of type
<literal>sample.contact.Contact</literal>, and then pass that
<literal>Contact</literal> to the <literal>AclManager</literal>. The
<literal>AclManager</literal> will then return an access control list
(ACL) that applies to the current <literal>Authentication</literal>.
Assuming that ACL contains one of the listed
<literal>requirePermission</literal>s, the voter will vote to grant
access. If the ACL does not contain one of the permissions defined
against the voter, the voter will vote to deny access.
<literal>BasicAclEntryVoter</literal> is an important class as it
allows you to build truly complex applications with domain object
security entirely defined in the application context. If you're
interested in learning more about Acegi Security's ACL capabilities
and how best to apply them, please see the ACL and "After Invocation"
sections of this reference guide, and the Contacts sample
application.</para>
<para>It is also possible to implement a custom
<literal>AccessDecisionVoter</literal>. Several examples are provided
in Acegi Security unit tests, including
<literal>ContactSecurityVoter</literal> and
<literal>DenyVoter</literal>. The
<literal>ContactSecurityVoter</literal> abstains from voting decisions
where a <literal>CONTACT_OWNED_BY_CURRENT_USER</literal>
<literal>ConfigAttribute</literal> is not found. If voting, it queries
the <literal>MethodInvocation</literal> to extract the owner of the
<literal>Contact</literal> object that is subject of the method call.
It votes to grant access if the <literal>Contact</literal> owner
matches the principal presented in the
<literal>Authentication</literal> object. It could have just as easily
compared the <literal>Contact</literal> owner with some
<literal>GrantedAuthority</literal> the
<literal>Authentication</literal> object presented. All of this is
achieved with relatively few lines of code and demonstrates the
flexibility of the authorization model.</para>
<para>TODO: Remove references to the old ACL package when it's
deprecated, and have all references to the replacement package limited
to the chapter describing the new ACL implementation.</para>
</sect1>
<sect1 id="after-invocation">
<title>After Invocation Handling</title>
<para>Whilst the <literal>AccessDecisionManager</literal> is called by
the <literal>AbstractSecurityInterceptor</literal> before proceeding
with the secure object invocation, some applications need a way of
modifying the object actually returned by the secure object
invocation. Whilst you could easily implement your own AOP concern to
achieve this, Acegi Security provides a convenient hook that has
several concrete implementations that integrate with its ACL
capabilities.</para>
<para>Figure 5 illustrates Acegi Security's
<literal>AfterInvocationManager</literal> and its concrete
implementations.</para>
<para><mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/AfterInvocation.gif"
format="GIF" />
</imageobject>
<caption>
<para>Figure 5: After Invocation Implementation</para>
</caption>
</mediaobject></para>
<para>Like many other parts of Acegi Security,
<literal>AfterInvocationManager</literal> has a single concrete
implementation, <literal>AfterInvocationProvider</literal>, which
polls a list of <literal>AfterInvocationProvider</literal>s. Each
<literal>AfterInvocationProvider</literal> is allowed to modify the
return object or throw an <literal>AccessDeniedException</literal>.
Indeed multiple providers can modify the object, as the result of the
previous provider is passed to the next in the list. Let's now
consider our ACL-aware implementations of
<literal>AfterInvocationProvider</literal>.</para>
<para>Please be aware that if you're using
<literal>AfterInvocationManager</literal>, you will still need
configuration attributes that allow the
<literal>MethodSecurityInterceptor</literal>'s
<literal>AccessDecisionManager</literal> to allow an operation. If
you're using the typical Acegi Security included
<literal>AccessDecisionManager</literal> implementations, having no
configuration attributes defined for a particular secure method
invocation will cause each <literal>AccessDecisionVoter</literal> to
abstain from voting. In turn, if the
<literal>AccessDecisionManager</literal> property
"<literal>allowIfAllAbstainDecisions</literal>" is
<literal>false</literal>, an <literal>AccessDeniedException</literal>
will be thrown. You may avoid this potential issue by either (i)
setting "<literal>allowIfAllAbstainDecisions</literal>" to
<literal>true</literal> (although this is generally not recommended)
or (ii) simply ensure that there is at least one configuration
attribute that an <literal>AccessDecisionVoter</literal> will vote to
grant access for. This latter (recommended) approach is usually
achieved through a <literal>ROLE_USER</literal> or
<literal>ROLE_AUTHENTICATED</literal> configuration attribute</para>
<sect2 id="after-invocation-acl-aware">
<title>ACL-Aware AfterInvocationProviders</title>
<para>TODO: This section will be removed when we deprecate the
existing ACL package. It should be discussed with the context of the
ACL implementation chapter instead.</para>
<para>A common services layer method we've all written at one stage
or another looks like this:</para>
<para><programlisting>public Contact getById(Integer id);</programlisting></para>
<para>Quite often, only principals with permission to read the
<literal>Contact</literal> should be allowed to obtain it. In this
situation the <literal>AccessDecisionManager</literal> approach
provided by the <literal>AbstractSecurityInterceptor</literal> will
not suffice. This is because the identity of the
<literal>Contact</literal> is all that is available before the
secure object is invoked. The
<literal>BasicAclAfterInvocationProvider</literal> delivers a
solution, and is configured as follows:</para>
<para><programlisting>&lt;bean id="afterAclRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider"&gt;
&lt;property name="aclManager"&gt;&lt;ref local="aclManager"/&gt;&lt;/property&gt;
&lt;property name="requirePermission"&gt;
&lt;list&gt;
&lt;ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/&gt;
&lt;ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>In the above example, the <literal>Contact</literal> will be
retrieved and passed to the
<literal>BasicAclEntryAfterInvocationProvider</literal>. The
provider will thrown an <literal>AccessDeniedException</literal> if
one of the listed <literal>requirePermission</literal>s is not held
by the <literal>Authentication</literal>. The
<literal>BasicAclEntryAfterInvocationProvider</literal> queries the
<literal>AclManager</literal> to determine the ACL that applies for
this domain object to this <literal>Authentication</literal>.</para>
<para>Similar to the
<literal>BasicAclEntryAfterInvocationProvider</literal> is
<literal>BasicAclEntryAfterInvocationCollectionFilteringProvider</literal>.
It is designed to remove <literal>Collection</literal> or array
elements for which a principal does not have access. It never thrown
an <literal>AccessDeniedException</literal> - simply silently
removes the offending elements. The provider is configured as
follows:</para>
<para><programlisting>&lt;bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider"&gt;
&lt;property name="aclManager"&gt;&lt;ref local="aclManager"/&gt;&lt;/property&gt;
&lt;property name="requirePermission"&gt;
&lt;list&gt;
&lt;ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/&gt;
&lt;ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting></para>
<para>As you can imagine, the returned <literal>Object</literal>
must be a <literal>Collection</literal> or array for this provider
to operate. It will remove any element if the
<literal>AclManager</literal> indicates the
<literal>Authentication</literal> does not hold one of the listed
<literal>requirePermission</literal>s.</para>
<para>The Contacts sample application demonstrates these two
<literal>AfterInvocationProvider</literal>s.</para>
</sect2>
</sect1>
<sect1 id="authorization-taglibs">
<title>Authorization Tag Libraries</title>
<para><literal>AuthorizeTag</literal> is used to include content if
the current principal holds certain
<literal>GrantedAuthority</literal>s.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AuthorizeTag</literal>:</para>
<para><programlisting>&lt;authz:authorize ifAllGranted="ROLE_SUPERVISOR"&gt;
&lt;td&gt;
&lt;A HREF="del.htm?id=&lt;c:out value="${contact.id}"/&gt;"&gt;Del&lt;/A&gt;
&lt;/td&gt;
&lt;/authz:authorize&gt; </programlisting></para>
<para>This tag would cause the tag's body to be output if the
principal has been granted ROLE_SUPERVISOR.</para>
<para>The <literal>authz:authorize</literal> tag declares the
following attributes:</para>
<para><itemizedlist spacing="compact">
<listitem>
<para><literal>ifAllGranted</literal>: All the listed roles must
be granted for the tag to output its body.</para>
</listitem>
<listitem>
<para><literal>ifAnyGranted</literal>: Any of the listed roles
must be granted for the tag to output its body.</para>
</listitem>
<listitem>
<para><literal>ifNotGranted</literal>: None of the listed roles
must be granted for the tag to output its body.</para>
</listitem>
</itemizedlist></para>
<para>You'll note that in each attribute you can list multiple roles.
Simply separate the roles using a comma. The
<literal>authorize</literal> tag ignores whitespace in
attributes.</para>
<para>The tag library logically ANDs all of it's parameters together.
This means that if you combine two or more attributes, all attributes
must be true for the tag to output it's body. Don't add an
<literal>ifAllGranted="ROLE_SUPERVISOR"</literal>, followed by an
<literal>ifNotGranted="ROLE_SUPERVISOR"</literal>, or you'll be
surprised to never see the tag's body.</para>
<para>By requiring all attributes to return true, the authorize tag
allows you to create more complex authorization scenarios. For
example, you could declare an
<literal>ifAllGranted="ROLE_SUPERVISOR"</literal> and an
<literal>ifNotGranted="ROLE_NEWBIE_SUPERVISOR"</literal> in the same
tag, in order to prevent new supervisors from seeing the tag body.
However it would no doubt be simpler to use
<literal>ifAllGranted="ROLE_EXPERIENCED_SUPERVISOR"</literal> rather
than inserting NOT conditions into your design.</para>
<para>One last item: the tag verifies the authorizations in a specific
order: first <literal>ifNotGranted</literal>, then
<literal>ifAllGranted</literal>, and finally, <literal>if
AnyGranted</literal>.</para>
<para><literal>AclTag</literal> is used to include content if the
current principal has a ACL to the indicated domain object.</para>
<para>The following JSP fragment illustrates how to use the
<literal>AclTag</literal>:</para>
<para><programlisting>
&lt;authz:acl domainObject="${contact}" hasPermission="16,1"&gt;
&lt;td&gt;&lt;A HREF="&lt;c:url value="del.htm"&gt;&lt;c:param name="contactId" value="${contact.id}"/&gt;&lt;/c:url&gt;"&gt;Del&lt;/A&gt;&lt;/td&gt;
&lt;/authz:acl&gt;
</programlisting></para>
<para>This tag would cause the tag's body to be output if the
principal holds either permission 16 or permission 1 for the "contact"
domain object. The numbers are actually integers that are used with
<literal>AbstractBasicAclEntry</literal> bit masking. Please refer to
the ACL section of this reference guide to understand more about the
ACL capabilities of Acegi Security</para>
</sect1>
</chapter>
<chapter id="secure-object-impls">
<title>Secure Object Implementations</title>
<sect1 id="aop-alliance">
<title>AOP Alliance (MethodInvocation) Security Interceptor</title>
<para>To secure <literal>MethodInvocation</literal>s, developers
simply add a properly configured
<literal>MethodSecurityInterceptor</literal> into the application
context. Next the beans requiring security are chained into the
interceptor. This chaining is accomplished using Springs
<literal>ProxyFactoryBean</literal> or
<literal>BeanNameAutoProxyCreator</literal>, as commonly used by many
other parts of Spring (refer to the sample application for examples).
Alternatively, Acegi Security provides a
<literal>MethodDefinitionSourceAdvisor</literal> which may be used
with Spring's <literal>DefaultAdvisorAutoProxyCreator</literal> to
automatically chain the security interceptor in front of any beans
defined against the <literal>MethodSecurityInterceptor</literal>. The
<literal>MethodSecurityInterceptor</literal> itself is configured as
follows:</para>
<programlisting>&lt;bean id="bankManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;
&lt;property name="validateConfigAttributes"&gt;&lt;value&gt;true&lt;/value&gt;&lt;/property&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="accessDecisionManager"&gt;&lt;ref bean="accessDecisionManager"/&gt;&lt;/property&gt;
&lt;property name="runAsManager"&gt;&lt;ref bean="runAsManager"/&gt;&lt;/property&gt;
&lt;property name="afterInvocationManager"&gt;&lt;ref bean="afterInvocationManager"/&gt;&lt;/property&gt;
&lt;property name="objectDefinitionSource"&gt;
&lt;value&gt;
org.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
org.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting>
<para>As shown above, the <literal>MethodSecurityInterceptor</literal>
is configured with a reference to an
<literal>AuthenticationManager</literal>,
<literal>AccessDecisionManager</literal> and
<literal>RunAsManager</literal>, which are each discussed in separate
sections below. In this case we've also defined an
<literal>AfterInvocationManager</literal>, although this is entirely
optional. The <literal>MethodSecurityInterceptor</literal> is also
configured with configuration attributes that apply to different
method signatures. A full discussion of configuration attributes is
provided in the High Level Design section of this document.</para>
<para>The <literal>MethodSecurityInterceptor</literal> can be
configured with configuration attributes in three ways. The first is
via a property editor and the application context, which is shown
above. The second is via defining the configuration attributes in your
source code using Jakarta Commons Attributes or Java 5 Annotations.
The third is via writing your own
<literal>ObjectDefinitionSource</literal>, although this is beyond the
scope of this document. Irrespective of the approach used, the
<literal>ObjectDefinitionSource</literal> is responsible for returning
a <literal>ConfigAttributeDefinition</literal> object that contains
all of the configuration attributes associated with a single secure
method.</para>
<para>It should be noted that the
<literal>MethodSecurityInterceptor.setObjectDefinitionSource()</literal>
method actually expects an instance of
<literal>MethodDefinitionSource</literal>. This is a marker interface
which subclasses <literal>ObjectDefinitionSource</literal>. It simply
denotes the <literal>ObjectDefinitionSource</literal> understands
<literal>MethodInvocation</literal>s. In the interests of simplicity
we'll continue to refer to the
<literal>MethodDefinitionSource</literal> as an
<literal>ObjectDefinitionSource</literal>, as the distinction is of
little relevance to most users of the
<literal>MethodSecurityInterceptor</literal>.</para>
<para>If using the application context property editor approach (as
shown above), commas are used to delimit the different configuration
attributes that apply to a given method pattern. Each configuration
attribute is assigned into its own <literal>SecurityConfig</literal>
object. The <literal>SecurityConfig</literal> object is discussed in
the High Level Design section.</para>
<para>If you are using the Jakarta Commons Attributes approach, your
bean context will be configured differently:</para>
<programlisting>&lt;bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/&gt;
&lt;bean id="objectDefinitionSource" class="org.acegisecurity.intercept.method.MethodDefinitionAttributes"&gt;
&lt;property name="attributes"&gt;&lt;ref local="attributes"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="bankManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;
&lt;property name="validateConfigAttributes"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="accessDecisionManager"&gt;&lt;ref bean="accessDecisionManager"/&gt;&lt;/property&gt;
&lt;property name="runAsManager"&gt;&lt;ref bean="runAsManager"/&gt;&lt;/property&gt;
&lt;property name="objectDefinitionSource"&gt;&lt;ref bean="objectDefinitionSource"/&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting>
<para>In addition, your source code will contain Jakarta Commons
Attributes tags that refer to a concrete implementation of
<literal>ConfigAttribute</literal>. The following example uses the
<literal>SecurityConfig</literal> implementation to represent the
configuration attributes, and results in the same security
configuration as provided by the property editor approach
above:</para>
<programlisting>public interface BankManager {
/**
* @@SecurityConfig("ROLE_SUPERVISOR")
* @@SecurityConfig("RUN_AS_SERVER")
*/
public void deleteSomething(int id);
/**
* @@SecurityConfig("ROLE_SUPERVISOR")
* @@SecurityConfig("RUN_AS_SERVER")
*/
public void deleteAnother(int id);
/**
* @@SecurityConfig("ROLE_TELLER")
* @@SecurityConfig("ROLE_SUPERVISOR")
* @@SecurityConfig("BANKSECURITY_CUSTOMER")
* @@SecurityConfig("RUN_AS_SERVER")
*/
public float getBalance(int id);
}</programlisting>
<para>If you are using the Acegi Security Java 5 Annotations approach,
your bean context will be configured as follows:</para>
<programlisting>&lt;bean id="attributes" class="org.acegisecurity.annotation.SecurityAnnotationAttributes"/&gt;
&lt;bean id="objectDefinitionSource" class="org.acegisecurity.intercept.method.MethodDefinitionAttributes"&gt;
&lt;property name="attributes"&gt;&lt;ref local="attributes"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="bankManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"&gt;
&lt;property name="validateConfigAttributes"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="accessDecisionManager"&gt;&lt;ref bean="accessDecisionManager"/&gt;&lt;/property&gt;
&lt;property name="runAsManager"&gt;&lt;ref bean="runAsManager"/&gt;&lt;/property&gt;
&lt;property name="objectDefinitionSource"&gt;&lt;ref bean="objectDefinitionSource"/&gt;&lt;/property&gt;
&lt;/bean&gt; </programlisting>
<para>In addition, your source code will contain Acegi Java 5 Security
Annotations that represent the <literal>ConfigAttribute</literal>. The
following example uses the <literal>@Secured</literal> annotations to
represent the configuration attributes, and results in the same
security configuration as provided by the property editor
approach:</para>
<programlisting>import org.acegisecurity.annotation.Secured;
public interface BankManager {
/**
* Delete something
*/
@Secured({"ROLE_SUPERVISOR","RUN_AS_SERVER" })
public void deleteSomething(int id);
/**
* Delete another
*/
@Secured({"ROLE_SUPERVISOR","RUN_AS_SERVER" })
public void deleteAnother(int id);
/**
* Get balance
*/
@Secured({"ROLE_TELLER","ROLE_SUPERVISOR","BANKSECURITY_CUSTOMER","RUN_AS_SERVER" })
public float getBalance(int id);
}</programlisting>
<para>You might have noticed the
<literal>validateConfigAttributes</literal> property in the above
<literal>MethodSecurityInterceptor</literal> examples. When set to
<literal>true</literal> (the default), at startup time the
<literal>MethodSecurityInterceptor</literal> will evaluate if the
provided configuration attributes are valid. It does this by checking
each configuration attribute can be processed by either the
<literal>AccessDecisionManager</literal> or the
<literal>RunAsManager</literal>. If neither of these can process a
given configuration attribute, an exception is thrown. If using the
Jakarta Commons Attributes method of configuration, you should set
<literal>validateConfigAttributes</literal> to
<literal>false</literal>.</para>
<para>Please note that when using
<literal>BeanNameAutoProxyCreator</literal> to create the required
proxy for security, the configuration must contain the property
<literal>proxyTargetClass</literal> set to <literal>true</literal>.
Otherwise, the method passed to
<literal>MethodSecurityInterceptor.invoke</literal> is the proxy's
caller, not the proxy's target. Note that this introduces a
requirement on CGLIB. See an example of using
<literal>BeanNameAutoProxyCreator</literal> below:</para>
<programlisting>&lt;bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"&gt;
&lt;property name="interceptorNames"&gt;
&lt;list&gt;&lt;value&gt;methodSecurityInterceptor&lt;/value&gt;&lt;/list&gt;
&lt;/property&gt;
&lt;property name="beanNames"&gt;
&lt;list&gt;&lt;value&gt;targetObjectName&lt;/value&gt;&lt;/list&gt;
&lt;/property&gt;
&lt;property name="proxyTargetClass" value="true"/&gt;
&lt;/bean&gt; </programlisting>
</sect1>
<sect1 id="aspectj">
<title>AspectJ (JoinPoint) Security Interceptor</title>
<para>The AspectJ security interceptor is very similar to the AOP
Alliance security interceptor discussed in the previous section.
Indeed we will only discuss the differences in this section.</para>
<para>The AspectJ interceptor is named
<literal>AspectJSecurityInterceptor</literal>. Unlike the AOP Alliance
security interceptor, which relies on the Spring application context
to weave in the security interceptor via proxying, the
<literal>AspectJSecurityInterceptor</literal> is weaved in via the
AspectJ compiler. It would not be uncommon to use both types of
security interceptors in the same application, with
<literal>AspectJSecurityInterceptor</literal> being used for domain
object instance security and the AOP Alliance
<literal>MethodSecurityInterceptor</literal> being used for services
layer security.</para>
<para>Let's first consider how the
<literal>AspectJSecurityInterceptor</literal> is configured in the
Spring application context:</para>
<programlisting>&lt;bean id="bankManagerSecurity" class="org.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor"&gt;
&lt;property name="validateConfigAttributes"&gt;&lt;value&gt;true&lt;/value&gt;&lt;/property&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="accessDecisionManager"&gt;&lt;ref bean="accessDecisionManager"/&gt;&lt;/property&gt;
&lt;property name="runAsManager"&gt;&lt;ref bean="runAsManager"/&gt;&lt;/property&gt;
&lt;property name="afterInvocationManager"&gt;&lt;ref bean="afterInvocationManager"/&gt;&lt;/property&gt;
&lt;property name="objectDefinitionSource"&gt;
&lt;value&gt;
org.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
org.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting>
<para>As you can see, aside from the class name, the
<literal>AspectJSecurityInterceptor</literal> is exactly the same as
the AOP Alliance security interceptor. Indeed the two interceptors can
share the same <literal>objectDefinitionSource</literal>, as the
<literal>ObjectDefinitionSource</literal> works with
<literal>java.lang.reflect.Method</literal>s rather than an AOP
library-specific class. Of course, your access decisions have access
to the relevant AOP library-specific invocation (ie
<literal>MethodInvocation</literal> or <literal>JoinPoint</literal>)
and as such can consider a range of addition criteria when making
access decisions (such as method arguments).</para>
<para>Next you'll need to define an AspectJ <literal>aspect</literal>.
For example:</para>
<programlisting>package org.acegisecurity.samples.aspectj;
import org.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor;
import org.acegisecurity.intercept.method.aspectj.AspectJCallback;
import org.springframework.beans.factory.InitializingBean;
public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
private AspectJSecurityInterceptor securityInterceptor;
pointcut domainObjectInstanceExecution(): target(PersistableEntity)
&amp;&amp; execution(public * *(..)) &amp;&amp; !within(DomainObjectInstanceSecurityAspect);
Object around(): domainObjectInstanceExecution() {
if (this.securityInterceptor != null) {
AspectJCallback callback = new AspectJCallback() {
public Object proceedWithObject() {
return proceed();
}
};
return this.securityInterceptor.invoke(thisJoinPoint, callback);
} else {
return proceed();
}
}
public AspectJSecurityInterceptor getSecurityInterceptor() {
return securityInterceptor;
}
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
public void afterPropertiesSet() throws Exception {
if (this.securityInterceptor == null)
throw new IllegalArgumentException("securityInterceptor required");
}
}</programlisting>
<para>In the above example, the security interceptor will be applied
to every instance of <literal>PersistableEntity</literal>, which is an
abstract class not shown (you can use any other class or
<literal>pointcut</literal> expression you like). For those curious,
<literal>AspectJCallback</literal> is needed because the
<literal>proceed();</literal> statement has special meaning only
within an <literal>around()</literal> body. The
<literal>AspectJSecurityInterceptor</literal> calls this anonymous
<literal>AspectJCallback</literal> class when it wants the target
object to continue.</para>
<para>You will need to configure Spring to load the aspect and wire it
with the <literal>AspectJSecurityInterceptor</literal>. A bean
declaration which achieves this is shown below:</para>
<programlisting>
&lt;bean id="domainObjectInstanceSecurityAspect"
class="org.acegisecurity.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf"&gt;
&lt;property name="securityInterceptor"&gt;&lt;ref bean="aspectJSecurityInterceptor"/&gt;&lt;/property&gt;
&lt;/bean&gt;
</programlisting>
<para>That's it! Now you can create your beans from anywhere within
your application, using whatever means you think fit (eg <literal>new
Person();</literal>) and they will have the security interceptor
applied.</para>
</sect1>
<sect1 id="filter-invocation-authorization">
<title>FilterInvocation Security Interceptor</title>
<para>To secure <literal>FilterInvocation</literal>s, developers need
to add a filter to their <literal>web.xml</literal> that delegates to
the <literal>FilterSecurityInterceptor</literal>. A typical
configuration example is provided below:</para>
<programlisting>&lt;filter&gt;
&lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;
&lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;targetClass&lt;/param-name&gt;
&lt;param-value&gt;org.acegisecurity.intercept.web.FilterSecurityInterceptor&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;</programlisting>
<para>Notice that the filter is actually a
<literal>FilterToBeanProxy</literal>. Most of the filters used by
Acegi Security use this class. Refer to the Filters section to learn
more about this bean.</para>
<para>In the application context you will need to configure three
beans:</para>
<programlisting>&lt;bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"&gt;
&lt;property name="authenticationEntryPoint"&gt;&lt;ref local="authenticationEntryPoint"/&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="authenticationEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"&gt;
&lt;property name="loginFormUrl"&gt;&lt;value&gt;/acegilogin.jsp&lt;/value&gt;&lt;/property&gt;
&lt;property name="forceHttps"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="accessDecisionManager"&gt;&lt;ref bean="accessDecisionManager"/&gt;&lt;/property&gt;
&lt;property name="objectDefinitionSource"&gt;
&lt;value&gt;
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/secure/super/.*\Z=ROLE_WE_DONT_HAVE
\A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_TELLER
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting>
<para>The <classname>ExceptionTranslationFilter</classname> provides
the bridge between Java exceptions and HTTP responses. It is solely
concerned with maintaining the user interface. This filter does not do
any actual security enforcement. If an
<exceptionname>AuthenticationException</exceptionname> is detected,
the filter will call the AuthenticationEntryPoint to commence the
authentication process (e.g. a user login).</para>
<para>The <literal>AuthenticationEntryPoint</literal> will be called
if the user requests a secure HTTP resource but they are not
authenticated. The class handles presenting the appropriate response
to the user so that authentication can begin. Three concrete
implementations are provided with Acegi Security:
<literal>AuthenticationProcessingFilterEntryPoint</literal> for
commencing a form-based authentication,
<literal>BasicProcessingFilterEntryPoint</literal> for commencing a
HTTP Basic authentication process, and
<literal>CasProcessingFilterEntryPoint</literal> for commencing a
JA-SIG Central Authentication Service (CAS) login. The
<literal>AuthenticationProcessingFilterEntryPoint</literal> and
<literal>CasProcessingFilterEntryPoint</literal> have optional
properties related to forcing the use of HTTPS, so please refer to the
JavaDocs if you require this.</para>
<para><literal>FilterSecurityInterceptor</literal> is responsible for
handling the security of HTTP resources. Like any other security
interceptor, it requires a reference to an
<literal>AuthenticationManager</literal> and an
<literal>AccessDecisionManager</literal>, which are both discussed in
separate sections below. The
<literal>FilterSecurityInterceptor</literal> is also configured with
configuration attributes that apply to different HTTP URL requests. A
full discussion of configuration attributes is provided in the High
Level Design section of this document.</para>
<para>The <literal>FilterSecurityInterceptor</literal> can be
configured with configuration attributes in two ways. The first is via
a property editor and the application context, which is shown above.
The second is via writing your own
<literal>ObjectDefinitionSource</literal>, although this is beyond the
scope of this document. Irrespective of the approach used, the
<literal>ObjectDefinitionSource</literal> is responsible for returning
a <literal>ConfigAttributeDefinition</literal> object that contains
all of the configuration attributes associated with a single secure
HTTP URL.</para>
<para>It should be noted that the
<literal>FilterSecurityInterceptor.setObjectDefinitionSource()</literal>
method actually expects an instance of
<literal>FilterInvocationDefinitionSource</literal>. This is a marker
interface which subclasses <literal>ObjectDefinitionSource</literal>.
It simply denotes the <literal>ObjectDefinitionSource</literal>
understands <literal>FilterInvocation</literal>s. In the interests of
simplicity we'll continue to refer to the
<literal>FilterInvocationDefinitionSource</literal> as an
<literal>ObjectDefinitionSource</literal>, as the distinction is of
little relevance to most users of the
<literal>FilterSecurityInterceptor</literal>.</para>
<para>If using the application context property editor approach (as
shown above), commas are used to delimit the different configuration
attributes that apply to each HTTP URL. Each configuration attribute
is assigned into its own <literal>SecurityConfig</literal> object. The
<literal>SecurityConfig</literal> object is discussed in the High
Level Design section. The <literal>ObjectDefinitionSource</literal>
created by the property editor,
<literal>FilterInvocationDefinitionSource</literal>, matches
configuration attributes against <literal>FilterInvocations</literal>
based on expression evaluation of the request URL. Two standard
expression syntaxes are supported. The default is to treat all
expressions as regular expressions. Alternatively, the presence of a
<literal>PATTERN_TYPE_APACHE_ANT</literal> directive will cause all
expressions to be treated as Apache Ant paths. It is not possible to
mix expression syntaxes within the same definition. For example, the
earlier configuration could be generated using Apache Ant paths as
follows:</para>
<programlisting>&lt;bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt;
&lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
&lt;property name="accessDecisionManager"&gt;&lt;ref bean="accessDecisionManager"/&gt;&lt;/property&gt;
&lt;property name="runAsManager"&gt;&lt;ref bean="runAsManager"/&gt;&lt;/property&gt;
&lt;property name="objectDefinitionSource"&gt;
&lt;value&gt;
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/secure/super/**=ROLE_WE_DONT_HAVE
/secure/**=ROLE_SUPERVISOR,ROLE_TELLER
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt; </programlisting>
<para>Irrespective of the type of expression syntax used, expressions
are always evaluated in the order they are defined. Thus it is
important that more specific expressions are defined higher in the
list than less specific expressions. This is reflected in our example
above, where the more specific <literal>/secure/super/</literal>
pattern appears higher than the less specific
<literal>/secure/</literal> pattern. If they were reversed, the
<literal>/secure/</literal> pattern would always match and the
<literal>/secure/super/</literal> pattern would never be
evaluated.</para>
<para>The special keyword
<literal>CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON</literal> causes
the <literal>FilterInvocationDefinitionSource</literal> to
automatically convert a request URL to lowercase before comparison
against the expressions. Whilst by default the case of the request URL
is not converted, it is generally recommended to use
<literal>CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON</literal> and
write each expression assuming lowercase.</para>
<para>As with other security interceptors, the
<literal>validateConfigAttributes</literal> property is observed. When
set to <literal>true</literal> (the default), at startup time the
<literal>FilterSecurityInterceptor</literal> will evaluate if the
provided configuration attributes are valid. It does this by checking
each configuration attribute can be processed by either the
<literal>AccessDecisionManager</literal> or the
<literal>RunAsManager</literal>. If neither of these can process a
given configuration attribute, an exception is thrown.</para>
</sect1>
</chapter>
<chapter id="domain-acls">
<title>Domain Object Security</title>
<section id="domain-acls-overview">
<title>Overview</title>
<para>Complex applications often will find the need to define access
permissions not simply at a web request or method invocation level.
Instead, security decisions need to comprise both who
(<literal>Authentication</literal>), where
(<literal>MethodInvocation</literal>) and what
(<literal>SomeDomainObject</literal>). In other words, authorization
decisions also need to consider the actual domain object instance
subject of a method invocation.</para>
<para>Imagine you're designing an application for a pet clinic. There
will be two main groups of users of your Spring-based application:
staff of the pet clinic, as well as the pet clinic's customers. The
staff will have access to all of the data, whilst your customers will
only be able to see their own customer records. To make it a little
more interesting, your customers can allow other users to see their
customer records, such as their "puppy preschool "mentor or president
of their local "Pony Club". Using Acegi Security as the foundation,
you have several approaches that can be used:<orderedlist>
<listitem>
<para>Write your business methods to enforce the security. You
could consult a collection within the
<literal>Customer</literal> domain object instance to determine
which users have access. By using the
<literal>SecurityContextHolder.getContext().getAuthentication()</literal>,
you'll be able to access the <literal>Authentication</literal>
object.</para>
</listitem>
<listitem>
<para>Write an <literal>AccessDecisionVoter</literal> to enforce
the security from the <literal>GrantedAuthority[]</literal>s
stored in the <literal>Authentication</literal> object. This
would mean your <literal>AuthenticationManager</literal> would
need to populate the <literal>Authentication</literal> with
custom <literal>GrantedAuthority</literal>[]s representing each
of the <literal>Customer</literal> domain object instances the
principal has access to.</para>
</listitem>
<listitem>
<para>Write an <literal>AccessDecisionVoter</literal> to enforce
the security and open the target <literal>Customer</literal>
domain object directly. This would mean your voter needs access
to a DAO that allows it to retrieve the
<literal>Customer</literal> object. It would then access the
<literal>Customer</literal> object's collection of approved
users and make the appropriate decision.</para>
</listitem>
</orderedlist></para>
<para>Each one of these approaches is perfectly legitimate. However,
the first couples your authorization checking to your business code.
The main problems with this include the enhanced difficulty of unit
testing and the fact it would be more difficult to reuse the
<literal>Customer</literal> authorization logic elsewhere. Obtaining
the <literal>GrantedAuthority[]</literal>s from the
<literal>Authentication</literal> object is also fine, but will not
scale to large numbers of <literal>Customer</literal>s. If a user
might be able to access 5,000 <literal>Customer</literal>s (unlikely
in this case, but imagine if it were a popular vet for a large Pony
Club!) the amount of memory consumed and time required to construct
the <literal>Authentication</literal> object would be undesirable. The
final method, opening the <literal>Customer</literal> directly from
external code, is probably the best of the three. It achieves
separation of concerns, and doesn't misuse memory or CPU cycles, but
it is still inefficient in that both the
<literal>AccessDecisionVoter</literal> and the eventual business
method itself will perform a call to the DAO responsible for
retrieving the <literal>Customer</literal> object. Two accesses per
method invocation is clearly undesirable. In addition, with every
approach listed you'll need to write your own access control list
(ACL) persistence and business logic from scratch.</para>
<para>Fortunately, there is another alternative, which we'll talk
about below.</para>
</section>
<section id="domain-acls-basic">
<title>Basic ACL Package</title>
<para>Please note that our Basic ACL services are currently being
refactored. We expect release 1.1.0 will contain this new code.
Planned code is already in the Acegi Security Subversion sandbox, so
please check there if you have a new application requiring ACLs or are
in the planning stages. The Basic ACL services will be deprecated from
release 1.1.0.</para>
<para>The <literal>org.acegisecurity.acl</literal> package is very
simple, comprising only a handful of interfaces and a single class, as
shown in Figure 6. It provides the basic foundation for access control
list (ACL) lookups.</para>
<para><mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/ACLSecurity.gif"
format="GIF" />
</imageobject>
<caption>
<para>Figure 6: Access Control List Manager</para>
</caption>
</mediaobject></para>
<para>The central interface is <literal>AclManager</literal>, which is
defined by two methods:</para>
<para><programlisting>public AclEntry[] getAcls(java.lang.Object domainInstance);
public AclEntry[] getAcls(java.lang.Object domainInstance, Authentication authentication);</programlisting></para>
<para><literal>AclManager</literal> is intended to be used as a
collaborator against your business objects, or, more desirably,
<literal>AccessDecisionVoter</literal>s. This means you use Spring's
normal <literal>ApplicationContext</literal> features to wire up your
<literal>AccessDecisionVoter</literal> (or business method) with an
<literal>AclManager</literal>. Consideration was given to placing the
ACL information in the <literal>ContextHolder</literal>, but it was
felt this would be inefficient both in terms of memory usage as well
as the time spent loading potentially unused ACL information. The
trade-off of needing to wire up a collaborator for those objects
requiring ACL information is rather minor, particularly in a
Spring-managed application.</para>
<para>The first method of the <literal>AclManager</literal> will
return all ACLs applying to the domain object instance passed to it.
The second method does the same, but only returns those ACLs which
apply to the passed <literal>Authentication</literal> object.</para>
<para>The <literal>AclEntry</literal> interface returned by
<literal>AclManager</literal> is merely a marker interface. You will
need to provide an implementation that reflects that ACL permissions
for your application.</para>
<para>Rounding out the <literal>org.acegisecurity.acl</literal>
package is an <literal>AclProviderManager</literal> class, with a
corresponding <literal>AclProvider</literal> interface.
<literal>AclProviderManager</literal> is a concrete implementation of
<literal>AclManager</literal>, which iterates through registered
<literal>AclProvider</literal>s. The first
<literal>AclProvider</literal> that indicates it can authoritatively
provide ACL information for the presented domain object instance will
be used. This is very similar to the
<literal>AuthenticationProvider</literal> interface used for
authentication.</para>
<para>With this background, let's now look at a usable ACL
implementation.</para>
<para>Acegi Security includes a production-quality ACL provider
implementation, which is shown in Figure 7.</para>
<para><mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/BasicAclProvider.gif"
format="GIF" />
</imageobject>
<caption>
<para>Figure 7: Basic ACL Manager</para>
</caption>
</mediaobject></para>
<para>The implementation is based on integer masking, which is
commonly used for ACL permissions given its flexibility and speed.
Anyone who has used Unix's <literal>chmod</literal> command will know
all about this type of permission masking (eg <literal>chmod
777</literal>). You'll find the classes and interfaces for the integer
masking ACL package under
<literal>org.acegisecurity.acl.basic</literal>.</para>
<para>Extending the <literal>AclEntry</literal> interface is a
<literal>BasicAclEntry</literal> interface, with the main methods
shown below:</para>
<para><programlisting>public AclObjectIdentity getAclObjectIdentity();
public AclObjectIdentity getAclObjectParentIdentity();
public int getMask();
public java.lang.Object getRecipient();</programlisting></para>
<para>As shown, each <literal>BasicAclEntry</literal> has four main
properties. The <literal>mask</literal> is the integer that represents
the permissions granted to the <literal>recipient</literal>. The
<literal>aclObjectIdentity</literal> is able to identify the domain
object instance for which the ACL applies, and the
<literal>aclObjectParentIdentity</literal> optionally specifies the
parent of the domain object instance. Multiple
<literal>BasicAclEntry</literal>s usually exist against a single
domain object instance, and as suggested by the parent identity
property, permissions granted higher in the object hierarchy will
trickle down and be inherited (unless blocked by integer zero).</para>
<para><literal>BasicAclEntry</literal> implementations typically
provide convenience methods, such as
<literal>isReadAllowed()</literal>, to avoid application classes
needing to perform bit masking themselves. The
<literal>SimpleAclEntry</literal> and
<literal>AbstractBasicAclEntry</literal> demonstrate and provide much
of this bit masking logic.</para>
<para>The <literal>AclObjectIdentity</literal> itself is merely a
marker interface, so you need to provide implementations for your
domain objects. However, the package does include a
<literal>NamedEntityObjectIdentity</literal> implementation which will
suit many needs. The <literal>NamedEntityObjectIdentity</literal>
identifies a given domain object instance by the classname of the
instance and the identity of the instance. A
<literal>NamedEntityObjectIdentity</literal> can be constructed
manually (by calling the constructor and providing the classname and
identity <literal>String</literal>s), or by passing in any domain
object that contains a <literal>getId()</literal> method.</para>
<para>The actual <literal>AclProvider</literal> implementation is
named <literal>BasicAclProvider</literal>. It has adopted a similar
design to that used by the authentication-related
<literal>DaoAuthenticationProvder</literal>. Specifically, you define
a <literal>BasicAclDao</literal> against the provider, so different
ACL repository types can be accessed in a pluggable manner. The
<literal>BasicAclProvider</literal> also supports pluggable cache
providers (with Acegi Security including an implementation that fronts
EH-CACHE).</para>
<para>The <literal>BasicAclDao</literal> interface is very simple to
implement:</para>
<para><programlisting>public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity);</programlisting></para>
<para>A <literal>BasicAclDao</literal> implementation needs to
understand the presented <literal>AclObjectIdentity</literal> and how
it maps to a storage repository, find the relevant records, and create
appropriate <literal>BasicAclEntry</literal> objects and return
them.</para>
<para>Acegi Security includes a single <literal>BasicAclDao</literal>
implementation called <literal>JdbcDaoImpl</literal>. As implied by
the name, <literal>JdbcDaoImpl</literal> accesses ACL information from
a JDBC database. There is also an extended version of this DAO,
<literal>JdbcExtendedDaoImpl</literal>, which provides CRUD operations
on the JDBC database, although we won't discuss these features here.
The default database schema and some sample data will aid in
understanding its function:</para>
<para><programlisting>CREATE TABLE acl_object_identity (
id IDENTITY NOT NULL,
object_identity VARCHAR_IGNORECASE(250) NOT NULL,
parent_object INTEGER,
acl_class VARCHAR_IGNORECASE(250) NOT NULL,
CONSTRAINT unique_object_identity UNIQUE(object_identity),
FOREIGN KEY (parent_object) REFERENCES acl_object_identity(id)
);
CREATE TABLE acl_permission (
id IDENTITY NOT NULL,
acl_object_identity INTEGER NOT NULL,
recipient VARCHAR_IGNORECASE(100) NOT NULL,
mask INTEGER NOT NULL,
CONSTRAINT unique_recipient UNIQUE(acl_object_identity, recipient),
FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id)
);
INSERT INTO acl_object_identity VALUES (1, 'corp.DomainObject:1', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');
INSERT INTO acl_object_identity VALUES (2, 'corp.DomainObject:2', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry');
INSERT INTO acl_object_identity VALUES (3, 'corp.DomainObject:3', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry');
INSERT INTO acl_object_identity VALUES (4, 'corp.DomainObject:4', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry');
INSERT INTO acl_object_identity VALUES (5, 'corp.DomainObject:5', 3, 'org.acegisecurity.acl.basic.SimpleAclEntry');
INSERT INTO acl_object_identity VALUES (6, 'corp.DomainObject:6', 3, 'org.acegisecurity.acl.basic.SimpleAclEntry');
INSERT INTO acl_permission VALUES (null, 1, 'ROLE_SUPERVISOR', 1);
INSERT INTO acl_permission VALUES (null, 2, 'ROLE_SUPERVISOR', 0);
INSERT INTO acl_permission VALUES (null, 2, 'marissa', 2);
INSERT INTO acl_permission VALUES (null, 3, 'scott', 14);
INSERT INTO acl_permission VALUES (null, 6, 'scott', 1);</programlisting></para>
<para>As can be seen, database-specific constraints are used
extensively to ensure the integrity of the ACL information. If you
need to use a different database (Hypersonic SQL statements are shown
above), you should try to implement equivalent constraints. The
equivalent Oracle configuration is:</para>
<para><programlisting>CREATE TABLE ACL_OBJECT_IDENTITY (
ID number(19,0) not null,
OBJECT_IDENTITY varchar2(255) NOT NULL,
PARENT_OBJECT number(19,0),
ACL_CLASS varchar2(255) NOT NULL,
primary key (ID)
);
ALTER TABLE ACL_OBJECT_IDENTITY ADD CONTRAINT FK_PARENT_OBJECT foreign key (ID) references ACL_OBJECT_IDENTITY
CREATE SEQUENCE ACL_OBJECT_IDENTITY_SEQ;
CREATE OR REPLACE TRIGGER ACL_OBJECT_IDENTITY_ID
BEFORE INSERT ON ACL_OBJECT_IDENTITY
FOR EACH ROW
BEGIN
SELECT ACL_OBJECT_IDENTITY_SEQ.NEXTVAL INTO :new.id FROM dual;
END;
CREATE TABLE ACL_PERMISSION (
ID number(19,0) not null,
ACL_OBJECT_IDENTITY number(19,0) NOT NULL,
RECIPIENT varchar2(255) NOT NULL,
MASK number(19,0) NOT NULL,
primary key (ID)
);
ALTER TABLE ACL_PERMISSION ADD CONTRAINT UNIQUE_ID_RECIPIENT unique (acl_object_identity, recipient);
CREATE SEQUENCE ACL_PERMISSION_SEQ;
CREATE OR REPLACE TRIGGER ACL_PERMISSION_ID
BEFORE INSERT ON ACL_PERMISSION
FOR EACH ROW
BEGIN
SELECT ACL_PERMISSION_SEQ.NEXTVAL INTO :new.id FROM dual;
END;
&lt;bean id="basicAclExtendedDao" class="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl"&gt;
&lt;property name="dataSource"&gt;
&lt;ref bean="dataSource"/&gt;
&lt;/property&gt;
&lt;property name="objectPropertiesQuery" value="${acegi.objectPropertiesQuery}"/&gt;
&lt;/bean&gt;
&lt;prop key="acegi.objectPropertiesQuery"&gt;SELECT CHILD.ID, CHILD.OBJECT_IDENTITY, CHILD.ACL_CLASS, PARENT.OBJECT_IDENTITY as PARENT_OBJECT_IDENTITY FROM acl_object_identity as CHILD LEFT OUTER JOIN acl_object_identity as PARENT ON CHILD.parent_object=PARENT.id WHERE CHILD.object_identity = ?&lt;/prop&gt; </programlisting></para>
<para>The <literal>JdbcDaoImpl</literal> will only respond to requests
for <literal>NamedEntityObjectIdentity</literal>s. It converts such
identities into a single <literal>String</literal>, comprising
the<literal> NamedEntityObjectIdentity.getClassname()</literal> +
<literal>":"</literal> +
<literal>NamedEntityObjectIdentity.getId()</literal>. This yields the
type of <literal>object_identity</literal> values shown above. As
indicated by the sample data, each database row corresponds to a
single <literal>BasicAclEntry</literal>. As stated earlier and
demonstrated by <literal>corp.DomainObject:2</literal> in the above
sample data, each domain object instance will often have multiple
<literal>BasicAclEntry</literal>[]s.</para>
<para>As <literal>JdbcDaoImpl</literal> is required to return concrete
<literal>BasicAclEntry</literal> classes, it needs to know which
<literal>BasicAclEntry</literal> implementation it is to create and
populate. This is the role of the <literal>acl_class</literal> column.
<literal>JdbcDaoImpl</literal> will create the indicated class and set
its <literal>mask</literal>, <literal>recipient</literal>,
<literal>aclObjectIdentity</literal> and
<literal>aclObjectParentIdentity</literal> properties.</para>
<para>As you can probably tell from the sample data, the
<literal>parent_object_identity</literal> value can either be null or
in the same format as the <literal>object_identity</literal>. If
non-null, <literal>JdbcDaoImpl</literal> will create a
<literal>NamedEntityObjectIdentity</literal> to place inside the
returned <literal>BasicAclEntry</literal> class.</para>
<para>Returning to the <literal>BasicAclProvider</literal>, before it
can poll the <literal>BasicAclDao</literal> implementation it needs to
convert the domain object instance it was passed into an
<literal>AclObjectIdentity</literal>.
<literal>BasicAclProvider</literal> has a <literal>protected
AclObjectIdentity obtainIdentity(Object domainInstance)</literal>
method that is responsible for this. As a protected method, it enables
subclasses to easily override. The normal implementation checks
whether the passed domain object instance implements the
<literal>AclObjectIdentityAware</literal> interface, which is merely a
getter for an <literal>AclObjectIdentity</literal>. If the domain
object does implement this interface, that is the identity returned.
If the domain object does not implement this interface, the method
will attempt to create an <literal>AclObjectIdentity</literal> by
passing the domain object instance to the constructor of a class
defined by the
<literal>BasicAclProvider.getDefaultAclObjectIdentity()</literal>
method. By default the defined class is
<literal>NamedEntityObjectIdentity</literal>, which was described in
more detail above. Therefore, you will need to either (i) provide a
<literal>getId()</literal> method on your domain objects, (ii)
implement <literal>AclObjectIdentityAware</literal> on your domain
objects, (iii) provide an alternative
<literal>AclObjectIdentity</literal> implementation that will accept
your domain object in its constructor, or (iv) override the
<literal>obtainIdentity(Object)</literal> method.</para>
<para>Once the <literal>AclObjectIdentity</literal> of the domain
object instance is determined, the <literal>BasicAclProvider</literal>
will poll the DAO to obtain its <literal>BasicAclEntry</literal>[]s.
If any of the entries returned by the DAO indicate there is a parent,
that parent will be polled, and the process will repeat until there is
no further parent. The permissions assigned to a
<literal>recipient</literal> closest to the domain object instance
will always take priority and override any inherited permissions. From
the sample data above, the following inherited permissions would
apply:</para>
<para><programlisting>--- Mask integer 0 = no permissions
--- Mask integer 1 = administer
--- Mask integer 2 = read
--- Mask integer 6 = read and write permissions
--- Mask integer 14 = read and write and create permissions
---------------------------------------------------------------------
--- *** INHERITED RIGHTS FOR DIFFERENT INSTANCES AND RECIPIENTS ***
--- INSTANCE RECIPIENT PERMISSION(S) (COMMENT #INSTANCE)
---------------------------------------------------------------------
--- 1 ROLE_SUPERVISOR Administer
--- 2 ROLE_SUPERVISOR None (overrides parent #1)
--- marissa Read
--- 3 ROLE_SUPERVISOR Administer (from parent #1)
--- scott Read, Write, Create
--- 4 ROLE_SUPERVISOR Administer (from parent #1)
--- 5 ROLE_SUPERVISOR Administer (from parent #3)
--- scott Read, Write, Create (from parent #3)
--- 6 ROLE_SUPERVISOR Administer (from parent #3)
--- scott Administer (overrides parent #3)</programlisting></para>
<para>So the above explains how a domain object instance has its
<literal>AclObjectIdentity</literal> discovered, and the
<literal>BasicAclDao</literal> will be polled successively until an
array of inherited permissions is constructed for the domain object
instance. The final step is to determine the
<literal>BasicAclEntry</literal>[]s that are actually applicable to a
given <literal>Authentication</literal> object.</para>
<para>As you would recall, the <literal>AclManager</literal> (and all
delegates, up to and including <literal>BasicAclProvider</literal>)
provides a method which returns only those
<literal>BasicAclEntry</literal>[]s applying to a passed
<literal>Authentication</literal> object.
<literal>BasicAclProvider</literal> delivers this functionality by
delegating the filtering operation to an
<literal>EffectiveAclsResolver</literal> implementation. The default
implementation,
<literal>GrantedAuthorityEffectiveAclsResolver</literal>, will iterate
through the <literal>BasicAclEntry</literal>[]s and include only those
where the <literal>recipient</literal> is equal to either the
<literal>Authentication</literal>'s <literal>principal</literal> or
any of the <literal>Authentication</literal>'s
<literal>GrantedAuthority</literal>[]s. Please refer to the JavaDocs
for more information.</para>
<mediaobject>
<imageobject role="html">
<imagedata align="center" fileref="images/Permissions.gif"
format="GIF" />
</imageobject>
<caption>
<para>Figure 8: ACL Instantiation Approach</para>
</caption>
</mediaobject>
<para>The above figure explains the key relationships between objects
in the Basic ACL package.</para>
</section>
</chapter>
</part>
<part id="resources">
<title>Other Resources</title>
<partintro>
<para>In addition to this reference guide, a number of other resources
exist to help you learn how to use Acegi Security. These resources are
discussed in this section.</para>
</partintro>
<chapter id="sample-apps">
<title id="samples">Sample Applications</title>
<sect1 id="contacts-sample">
<title id="contacts">Contacts</title>
<para>Included with Acegi Security is a very simple application that
can demonstrate the basic security facilities provided by the system
(and confirm your Container Adapter is properly configured if you're
using one).</para>
<para>If you build from Subversion, the Contacts sample application
includes three deployable versions:
<literal>acegi-security-sample-contacts-filter.war</literal> is
configured with the HTTP Session Authentication approach.
Acegi<literal><literal>-security-sample-contacts-ca.war</literal></literal>
is configured to use a Container Adapter. Finally,
<literal>acegi-security-sample-contacts-cas.war</literal> is designed
to work with a JA-SIG CAS server. If you're just wanting to see how
the sample application works, please use
<literal><literal>acegi-security-sample-contacts-filter.war</literal></literal>
as it does not require special configuration of your container. This
is also the artifact included in official release ZIPs.</para>
<para>To deploy, simply copy the relevant WAR file from Acegi Security
distribution into your containers <literal>webapps</literal>
directory.</para>
<para>After starting your container, check the application can load.
Visit
<literal>http://localhost:</literal><literal><literal>8080/</literal>acegi-security-sample-contacts-filter</literal>
(or whichever URL is appropriate for your web container and the WAR
you deployed). A random contact should be displayed. Click "Refresh"
several times and you will see different contacts. The business method
that provides this random contact is not secured.</para>
<para>Next, click "Debug". You will be prompted to authenticate, and a
series of usernames and passwords are suggested on that page. Simply
authenticate with any of these and view the resulting page. It should
contain a success message similar to the following:</para>
<blockquote>
<para>Context on SecurityContextHolder is of type:
org.acegisecurity.context.SecurityContextImpl</para>
<para>The Context implements SecurityContext.</para>
<para>Authentication object is of type:
org.acegisecurity.adapters.PrincipalAcegiUserToken</para>
<para>Authentication object as a String:
org.acegisecurity.adapters.PrincipalAcegiUserToken@e9a7c2: Username:
marissa; Password: [PROTECTED]; Authenticated: true; Granted
Authorities: ROLE_TELLER, ROLE_SUPERVISOR</para>
<para>Authentication object holds the following granted
authorities:</para>
<para>ROLE_TELLER (getAuthority(): ROLE_TELLER)</para>
<para>ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR)</para>
<para>SUCCESS! Your [container adapter|web filter] appears to be
properly configured!</para>
</blockquote>
<para>If you receive a different message, and deployed
<literal>acegi-security-sample-contacts-ca.war</literal>, check you
have properly configured your Container Adapter as described elsewhere
in this reference guide.</para>
<para>Once you successfully receive the above message, return to the
sample application's home page and click "Manage". You can then try
out the application. Notice that only the contacts available to the
currently logged on user are displayed, and only users with
<literal>ROLE_SUPERVISOR</literal> are granted access to delete their
contacts. Behind the scenes, the
<literal>MethodSecurityInterceptor</literal> is securing the business
objects. If you're using
<literal><literal>acegi-security-sample-contacts-filter.war</literal></literal>
or <literal>acegi-security-sample-contacts-cas.war</literal>, the
<literal>FilterSecurityInterceptor</literal> is also securing the HTTP
requests. If using either of these WARs, be sure to try visiting
<literal>http://localhost:8080/contacts/secure/super</literal>, which
will demonstrate access being denied by the
<literal>FilterSecurityInterceptor</literal>. Note the sample
application enables you to modify the access control lists associated
with different contacts. Be sure to give this a try and understand how
it works by reviewing the sample application's application context XML
files.</para>
<para>The Contacts sample application also include a
<literal>client</literal> directory. Inside you will find a small
application that queries the backend business objects using several
web services protocols. This demonstrates how to use Acegi Security
for authentication with Spring remoting protocols. To try this client,
ensure your servlet container is still running the Contacts sample
application, and then execute <literal>client marissa koala</literal>.
The command-line parameters respectively represent the username to
use, and the password to use. Note that you may need to edit
<literal>client.properties</literal> to use a different target
URL.</para>
<para>Please note the sample application's <literal>client</literal>
does not currently support CAS. You can still give it a try, though,
if you're ambitious: try <literal>client _cas_stateless_
YOUR-SERVICE-TICKET-ID</literal>.</para>
</sect1>
<sect1 id="tutorial-sample">
<title>Tutorial Sample</title>
<para>Whilst the <link linkend="contacts-sample">Contacts
Sample</link> is quite advanced in that it illustrates the more
powerful features of domain object access control lists and so on,
sometimes you just want to start with a nice basic example. The
tutorial sample is intended to provide this for you.</para>
<para>The compiled tutorial is included in the distribution ZIP file,
ready to be deployed into your web container. Authentication is
handled by the <link
linkend="dao-provider">DaoAuthenticationProvider</link>, using the
<link linkend="in-memory-service">in-memory</link>
<literal>UserDetailsService</literal> that sources information from
the <literal>users.properties</literal> file located in the WAR's
<literal>/WEB-INF</literal> directory. The <link
linkend="form">form-based</link> authentication mechanism is used,
with the commonly-used <link linkend="remember-me">remember-me</link>
authentication provider used to automatically remember the login using
cookies.</para>
<para>In terms of authorization, to keep things simple we've
configured the tutorial to only perform some basic <link
linkend="filter-invocation-authorization">web filter
authorization</link>. We've wired two common <link
linkend="pre-invocation">pre-invocation access decision voters</link>,
being the <literal>RoleVoter</literal> and
<literal>AuthenticatedVoter</literal>, such that
<literal>ROLE_*</literal> configuration attributes and
<literal>IS_AUTHENTICATED_*</literal> configuration attributes may be
used. Of course, it's extremely easy to add in other providers, with
most users probably starting with some services-layer security using
<link linkend="aop-alliance">MethodSecurityInterceptor</link>.</para>
<para>We recommend you start with the tutorial sample, as the XML is
minimal and easy to follow. All of the needed <link
linkend="filters">filters</link> are configured properly, and using
best practise. Most importantly, you can easily this one XML file (and
its corresponding <literal>web.xml</literal> entries) to your existing
application. Only when this basic integration is achieved do we
suggest you attempt adding in method authorization or domain object
security.</para>
</sect1>
</chapter>
<chapter id="community">
<title>Community Support</title>
<sect1 id="jira">
<title>Use JIRA for Issue Tracking</title>
<para>Acegi Security uses JIRA to manage bug reports and enhancement
requests. If you find a bug, please log a report using JIRA. Do not
log it on the support forum, mailing list or by emailing the project's
developers. Such approaches are ad-hoc and we prefer to manage bugs
using a more formal process.</para>
<para>If possible, in your JIRA report please provide a JUnit test
that demonstrates any incorrect behaviour. Or, better yet, provide a
patch that corrects the issue. Similarly, enhancements are welcome to
be logged in JIRA, although we only accept commit enhancement requests
if you include corresponding unit tests. This is necessary to ensure
project test coverage is adequately maintained.</para>
<para>You can access JIRA at <ulink
url="http://opensource.atlassian.com/projects/spring/secure/BrowseProject.jspa?id=10040"></ulink>.</para>
</sect1>
<sect1 id="becoming-involved">
<title>Becoming Involved</title>
<para>We welcome you to become involved in Acegi Security project.
There are many ways of contributing, including reading the mailing
list and responding to questions from other people, writing new code,
improving existing code, assisting with documentation, developing
samples or tutorials, or simply making suggestions.</para>
<para>Please read our project policies web page that is available on
Acegi Security home page. This explains the path to become a
committer, and the administration approaches we use within the
project.</para>
</sect1>
<sect1 id="further-info">
<title>Further Information</title>
<para>Questions and comments on Acegi Security are welcome. Please use
the Spring Community Forum web site at <ulink
url="http://forum.springframework.org"></ulink> for all support
issues. Remember to use JIRA for bug reports, as explained above.
Everyone is also welcome to join the Acegisecurity-developer mailing
list and participate in design discussions. It's also a good way of
finding out what's happening with regard to release timing, and the
traffic volume is quite light. Finally, our project home page (where
you can obtain the latest release of the project and convenient links
to Subversion, JIRA, mailing lists, forums etc) is at <ulink
url="http://acegisecurity.org"></ulink>.</para>
</sect1>
</chapter>
</part>
</book>