diff --git a/docbook/images/admons/blank.png b/docbook/images/admons/blank.png
new file mode 100644
index 0000000000..764bf4f0c3
Binary files /dev/null and b/docbook/images/admons/blank.png differ
diff --git a/docbook/images/admons/caution.gif b/docbook/images/admons/caution.gif
new file mode 100644
index 0000000000..d9f5e5b1bc
Binary files /dev/null and b/docbook/images/admons/caution.gif differ
diff --git a/docbook/images/admons/caution.png b/docbook/images/admons/caution.png
new file mode 100644
index 0000000000..5b7809ca4a
Binary files /dev/null and b/docbook/images/admons/caution.png differ
diff --git a/docbook/images/admons/caution.tif b/docbook/images/admons/caution.tif
new file mode 100644
index 0000000000..4a282948c4
Binary files /dev/null and b/docbook/images/admons/caution.tif differ
diff --git a/docbook/images/admons/draft.png b/docbook/images/admons/draft.png
new file mode 100644
index 0000000000..0084708c9b
Binary files /dev/null and b/docbook/images/admons/draft.png differ
diff --git a/docbook/images/admons/home.gif b/docbook/images/admons/home.gif
new file mode 100644
index 0000000000..6784f5bb01
Binary files /dev/null and b/docbook/images/admons/home.gif differ
diff --git a/docbook/images/admons/home.png b/docbook/images/admons/home.png
new file mode 100644
index 0000000000..cbb711de71
Binary files /dev/null and b/docbook/images/admons/home.png differ
diff --git a/docbook/images/admons/important.gif b/docbook/images/admons/important.gif
new file mode 100644
index 0000000000..6795d9a819
Binary files /dev/null and b/docbook/images/admons/important.gif differ
diff --git a/docbook/images/admons/important.png b/docbook/images/admons/important.png
new file mode 100644
index 0000000000..12c90f607a
Binary files /dev/null and b/docbook/images/admons/important.png differ
diff --git a/docbook/images/admons/important.tif b/docbook/images/admons/important.tif
new file mode 100644
index 0000000000..184de63711
Binary files /dev/null and b/docbook/images/admons/important.tif differ
diff --git a/docbook/images/admons/next.gif b/docbook/images/admons/next.gif
new file mode 100644
index 0000000000..aa1516e691
Binary files /dev/null and b/docbook/images/admons/next.gif differ
diff --git a/docbook/images/admons/next.png b/docbook/images/admons/next.png
new file mode 100644
index 0000000000..45835bf89a
Binary files /dev/null and b/docbook/images/admons/next.png differ
diff --git a/docbook/images/admons/note.gif b/docbook/images/admons/note.gif
new file mode 100644
index 0000000000..f329d359e5
Binary files /dev/null and b/docbook/images/admons/note.gif differ
diff --git a/docbook/images/admons/note.png b/docbook/images/admons/note.png
new file mode 100644
index 0000000000..d0c3c645ab
Binary files /dev/null and b/docbook/images/admons/note.png differ
diff --git a/docbook/images/admons/note.tif b/docbook/images/admons/note.tif
new file mode 100644
index 0000000000..08644d6b5d
Binary files /dev/null and b/docbook/images/admons/note.tif differ
diff --git a/docbook/images/admons/prev.gif b/docbook/images/admons/prev.gif
new file mode 100644
index 0000000000..64ca8f3c7c
Binary files /dev/null and b/docbook/images/admons/prev.gif differ
diff --git a/docbook/images/admons/prev.png b/docbook/images/admons/prev.png
new file mode 100644
index 0000000000..cf24654f8a
Binary files /dev/null and b/docbook/images/admons/prev.png differ
diff --git a/docbook/images/admons/tip.gif b/docbook/images/admons/tip.gif
new file mode 100644
index 0000000000..823f2b417c
Binary files /dev/null and b/docbook/images/admons/tip.gif differ
diff --git a/docbook/images/admons/tip.png b/docbook/images/admons/tip.png
new file mode 100644
index 0000000000..5c4aab3bb3
Binary files /dev/null and b/docbook/images/admons/tip.png differ
diff --git a/docbook/images/admons/tip.tif b/docbook/images/admons/tip.tif
new file mode 100644
index 0000000000..4a3d8c75fd
Binary files /dev/null and b/docbook/images/admons/tip.tif differ
diff --git a/docbook/images/admons/toc-blank.png b/docbook/images/admons/toc-blank.png
new file mode 100644
index 0000000000..6ffad17a0c
Binary files /dev/null and b/docbook/images/admons/toc-blank.png differ
diff --git a/docbook/images/admons/toc-minus.png b/docbook/images/admons/toc-minus.png
new file mode 100644
index 0000000000..abbb020c8e
Binary files /dev/null and b/docbook/images/admons/toc-minus.png differ
diff --git a/docbook/images/admons/toc-plus.png b/docbook/images/admons/toc-plus.png
new file mode 100644
index 0000000000..941312ce0d
Binary files /dev/null and b/docbook/images/admons/toc-plus.png differ
diff --git a/docbook/images/admons/up.gif b/docbook/images/admons/up.gif
new file mode 100644
index 0000000000..aabc2d0165
Binary files /dev/null and b/docbook/images/admons/up.gif differ
diff --git a/docbook/images/admons/up.png b/docbook/images/admons/up.png
new file mode 100644
index 0000000000..07634de26b
Binary files /dev/null and b/docbook/images/admons/up.png differ
diff --git a/docbook/images/admons/warning.gif b/docbook/images/admons/warning.gif
new file mode 100644
index 0000000000..3adf191293
Binary files /dev/null and b/docbook/images/admons/warning.gif differ
diff --git a/docbook/images/admons/warning.png b/docbook/images/admons/warning.png
new file mode 100644
index 0000000000..1c33db8f34
Binary files /dev/null and b/docbook/images/admons/warning.png differ
diff --git a/docbook/images/admons/warning.tif b/docbook/images/admons/warning.tif
new file mode 100644
index 0000000000..7b6611ec7a
Binary files /dev/null and b/docbook/images/admons/warning.tif differ
diff --git a/docbook/images/callouts/1.gif b/docbook/images/callouts/1.gif
new file mode 100644
index 0000000000..0d66977193
Binary files /dev/null and b/docbook/images/callouts/1.gif differ
diff --git a/docbook/images/callouts/1.png b/docbook/images/callouts/1.png
new file mode 100644
index 0000000000..7d473430b7
Binary files /dev/null and b/docbook/images/callouts/1.png differ
diff --git a/docbook/images/callouts/10.gif b/docbook/images/callouts/10.gif
new file mode 100644
index 0000000000..fb50b06d15
Binary files /dev/null and b/docbook/images/callouts/10.gif differ
diff --git a/docbook/images/callouts/10.png b/docbook/images/callouts/10.png
new file mode 100644
index 0000000000..997bbc8246
Binary files /dev/null and b/docbook/images/callouts/10.png differ
diff --git a/docbook/images/callouts/11.gif b/docbook/images/callouts/11.gif
new file mode 100644
index 0000000000..9f5dba4f8d
Binary files /dev/null and b/docbook/images/callouts/11.gif differ
diff --git a/docbook/images/callouts/11.png b/docbook/images/callouts/11.png
new file mode 100644
index 0000000000..ce47dac3f5
Binary files /dev/null and b/docbook/images/callouts/11.png differ
diff --git a/docbook/images/callouts/12.gif b/docbook/images/callouts/12.gif
new file mode 100644
index 0000000000..a373d0b4f4
Binary files /dev/null and b/docbook/images/callouts/12.gif differ
diff --git a/docbook/images/callouts/12.png b/docbook/images/callouts/12.png
new file mode 100644
index 0000000000..31daf4e2f2
Binary files /dev/null and b/docbook/images/callouts/12.png differ
diff --git a/docbook/images/callouts/13.gif b/docbook/images/callouts/13.gif
new file mode 100644
index 0000000000..b00b1637bd
Binary files /dev/null and b/docbook/images/callouts/13.gif differ
diff --git a/docbook/images/callouts/13.png b/docbook/images/callouts/13.png
new file mode 100644
index 0000000000..14021a89c2
Binary files /dev/null and b/docbook/images/callouts/13.png differ
diff --git a/docbook/images/callouts/14.gif b/docbook/images/callouts/14.gif
new file mode 100644
index 0000000000..6d6642ee96
Binary files /dev/null and b/docbook/images/callouts/14.gif differ
diff --git a/docbook/images/callouts/14.png b/docbook/images/callouts/14.png
new file mode 100644
index 0000000000..64014b75fe
Binary files /dev/null and b/docbook/images/callouts/14.png differ
diff --git a/docbook/images/callouts/15.gif b/docbook/images/callouts/15.gif
new file mode 100644
index 0000000000..cdd7072d28
Binary files /dev/null and b/docbook/images/callouts/15.gif differ
diff --git a/docbook/images/callouts/15.png b/docbook/images/callouts/15.png
new file mode 100644
index 0000000000..0d65765fcf
Binary files /dev/null and b/docbook/images/callouts/15.png differ
diff --git a/docbook/images/callouts/2.gif b/docbook/images/callouts/2.gif
new file mode 100644
index 0000000000..100ff79f01
Binary files /dev/null and b/docbook/images/callouts/2.gif differ
diff --git a/docbook/images/callouts/2.png b/docbook/images/callouts/2.png
new file mode 100644
index 0000000000..5d09341b2f
Binary files /dev/null and b/docbook/images/callouts/2.png differ
diff --git a/docbook/images/callouts/3.gif b/docbook/images/callouts/3.gif
new file mode 100644
index 0000000000..5008ca7dbc
Binary files /dev/null and b/docbook/images/callouts/3.gif differ
diff --git a/docbook/images/callouts/3.png b/docbook/images/callouts/3.png
new file mode 100644
index 0000000000..ef7b700471
Binary files /dev/null and b/docbook/images/callouts/3.png differ
diff --git a/docbook/images/callouts/4.gif b/docbook/images/callouts/4.gif
new file mode 100644
index 0000000000..0e5617d2f2
Binary files /dev/null and b/docbook/images/callouts/4.gif differ
diff --git a/docbook/images/callouts/4.png b/docbook/images/callouts/4.png
new file mode 100644
index 0000000000..adb8364eb5
Binary files /dev/null and b/docbook/images/callouts/4.png differ
diff --git a/docbook/images/callouts/5.gif b/docbook/images/callouts/5.gif
new file mode 100644
index 0000000000..9bc75ada64
Binary files /dev/null and b/docbook/images/callouts/5.gif differ
diff --git a/docbook/images/callouts/5.png b/docbook/images/callouts/5.png
new file mode 100644
index 0000000000..4d7eb46002
Binary files /dev/null and b/docbook/images/callouts/5.png differ
diff --git a/docbook/images/callouts/6.gif b/docbook/images/callouts/6.gif
new file mode 100644
index 0000000000..d396407074
Binary files /dev/null and b/docbook/images/callouts/6.gif differ
diff --git a/docbook/images/callouts/6.png b/docbook/images/callouts/6.png
new file mode 100644
index 0000000000..0ba694af6c
Binary files /dev/null and b/docbook/images/callouts/6.png differ
diff --git a/docbook/images/callouts/7.gif b/docbook/images/callouts/7.gif
new file mode 100644
index 0000000000..c90b2f3df0
Binary files /dev/null and b/docbook/images/callouts/7.gif differ
diff --git a/docbook/images/callouts/7.png b/docbook/images/callouts/7.png
new file mode 100644
index 0000000000..472e96f8ac
Binary files /dev/null and b/docbook/images/callouts/7.png differ
diff --git a/docbook/images/callouts/8.gif b/docbook/images/callouts/8.gif
new file mode 100644
index 0000000000..6fe3287d25
Binary files /dev/null and b/docbook/images/callouts/8.gif differ
diff --git a/docbook/images/callouts/8.png b/docbook/images/callouts/8.png
new file mode 100644
index 0000000000..5e60973c21
Binary files /dev/null and b/docbook/images/callouts/8.png differ
diff --git a/docbook/images/callouts/9.gif b/docbook/images/callouts/9.gif
new file mode 100644
index 0000000000..bc5c8125b0
Binary files /dev/null and b/docbook/images/callouts/9.gif differ
diff --git a/docbook/images/callouts/9.png b/docbook/images/callouts/9.png
new file mode 100644
index 0000000000..a0676d26cc
Binary files /dev/null and b/docbook/images/callouts/9.png differ
diff --git a/docbook/images/logo.gif b/docbook/images/logo.gif
new file mode 100644
index 0000000000..38bac7e01a
Binary files /dev/null and b/docbook/images/logo.gif differ
diff --git a/docbook/images/logo.psd b/docbook/images/logo.psd
new file mode 100644
index 0000000000..684ad2e078
Binary files /dev/null and b/docbook/images/logo.psd differ
diff --git a/docbook/index.xml b/docbook/index.xml
new file mode 100644
index 0000000000..7310a61b98
--- /dev/null
+++ b/docbook/index.xml
@@ -0,0 +1,4016 @@
+
+
+
+
+
+ Acegi Security System for Spring
+
+ Reference Documentation
+
+ 0.7
+
+
+
+ Ben
+
+ Alex
+
+
+
+
+
+
+
+ Preface
+
+ This document provides a reference guide to the Acegi Security
+ System for Spring, which is a series of classes that deliver
+ authentication and authorization services within the Spring
+ Framework.
+
+ I would like to acknowledge this reference was prepared using the
+ DocBook configuration included with the Spring Framework. The Spring team
+ in turn acknowledge Chris Bauer (Hibernate) for his assistance with their
+ DocBook.
+
+
+
+ Security
+
+
+ Before You Begin
+
+ For your security, each official release JAR of Acegi Security has
+ been signed by the project leader. This does not in any way alter the
+ liability disclaimer contained in the License, but it does ensure you
+ are using a properly reviewed, official build of Acegi Security. Please
+ refer to the readme.txt file in the root of the
+ release distribution for instructions on how to validate the JARs are
+ correctly signed, and which certificate has been used to sign
+ them.
+
+
+
+ Introduction
+
+ The Acegi Security System for Spring provides authentication and
+ authorization capabilities for Spring-powered projects, with full
+ integration with popular web containers. The security architecture was
+ designed from the ground up using "The Spring Way" of development, which
+ includes using bean contexts, interceptors and interface-driven
+ programming. As a consequence, the Acegi Security System for Spring is
+ useful out-of-the-box for those seeking to secure their Spring-based
+ applications, and can be easily adapted to complex customized
+ requirements.
+
+ Security involves two distinct operations, authentication and
+ authorization. The former relates to resolving whether or not a caller
+ is who they claim to be. Authorization on the other hand relates to
+ determining whether or not an authenticated caller is permitted to
+ perform a given operation.
+
+ Throughout the Acegi Security System for Spring, the user, system
+ or agent that needs to be authenticated is referred to as a "principal".
+ The security architecture does not have a notion of roles or groups,
+ which you may be familiar with from other security
+ implementations.
+
+
+ Current Status
+
+ The Acegi Security System for Spring is widely used by members
+ of the Spring Community. The APIs are considered stable and only minor
+ changes are expected. Having said that, like many other projects we
+ need to strike a balance between backward compatibility and
+ improvement. Effective version 0.6.1, Acegi Security uses the Apache
+ Portable Runtime Project versioning guidelines, available from
+ http://apr.apache.org/versioning.html.
+
+ Some improvements are currently intended prior to the 1.0.0
+ release. These are:
+
+
+
+ Replacing the Ant build with a Maven build. When this
+ happens the lib directory will no longer be
+ distributed in ZIP releases or hosted in CVS.
+
+
+
+ "Remember me" functionality. Some discussion on this can be
+ found at
+ http://sourceforge.net/mailarchive/forum.php?thread_id=5177499&forum_id=40659.
+
+
+
+ A sample web application which demonstrates the access
+ control list package.
+
+
+
+ Implementation of an
+ ObjectDefinitionSource that retrieves its
+ details from a database.
+
+
+
+ Deprecation of Acegi Security's various EH-CACHE-based cache
+ implementations. Instead Acegi Security will provide new cache
+ implementations which use Spring Framework's new (currently in
+ CVS) EhCacheManagerFactoryBean factory. The
+ deprecated classes may be removed from the 1.0.0 release.
+
+
+
+ Whilst this list is subject to change and not in any particular
+ order, none of the above improvements are likely to result in changes
+ to the API. The improvements are also relatively minor to implement.
+ Users of Acegi Security System for Spring should therefore be
+ comfortable depending on the current version of the project in their
+ applications.
+
+
+
+
+ High Level Design
+
+
+ Key Components
+
+ The Acegi Security System for Spring essentially comprises seven
+ key functional parts:
+
+
+
+ An Authentication object which holds the
+ principal, credentials and the authorities granted to the
+ principal. The object can also store additional information
+ associated with an authentication request, such as the source
+ TCP/IP address.
+
+
+
+ A ContextHolder which holds the
+ Authentication object in a
+ ThreadLocal-bound object.
+
+
+
+ An AuthenticationManager to authenticate
+ the Authentication object presented via the
+ ContextHolder.
+
+
+
+ An AccessDecisionManager to authorize a
+ given operation.
+
+
+
+ A RunAsManager to optionally replace the
+ Authentication object whilst a given operation
+ is being executed.
+
+
+
+ A "secure object" interceptor, which coordinates the
+ authentication, authorization, run-as replacement and execution of
+ a given operation.
+
+
+
+ An acess control list (ACL) management package, which can be
+ used to obtain ACLs for domain object instances.
+
+
+
+ Secure objects refer to any type of object that can have
+ security applied to it. A secure object must provide some form of
+ callback, so that the security interceptor can transparently do its
+ work as required, and callback the object when it is time for it to
+ proceed with the requested operation. If secure objects cannot provide
+ a native callback approach, a wrapper needs to be written so this
+ becomes possible.
+
+ Each secure object has its own package under
+ net.sf.acegisecurity.intercept. Every other package
+ in the security system is secure object independent, in that it can
+ support any type of secure object presented.
+
+ 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 that does not use
+ MethodInvocations. Most Spring applications will
+ simply use the three currently supported secure object types
+ (MethodInvocation, JoinPoint and
+ FilterInterceptor) with complete
+ transparency.
+
+ Each of the seven key parts is discussed in detail throughout
+ this document.
+
+
+
+ Supported Secure Objects
+
+ The Acegi Security System for Spring currently supports three
+ secure objects.
+
+ The first handles an AOP Alliance
+ MethodInvocation. This is the secure object type
+ used to protect Spring beans. Developers will generally use this
+ secure object type to secure their business objects. To make a
+ standard Spring-hosted bean available as a
+ MethodInvocation, the bean is simply published
+ through a ProxyFactoryBean or
+ BeanNameAutoProxyCreator or
+ DefaultAdvisorAutoProxyCreator. Most Spring
+ developers would already be familiar with these due to their use in
+ transactions and other areas of Spring.
+
+ The second type is an AspectJ JoinPoint.
+ AspectJ has a particular use in securing domain object instances, as
+ these are most often managed outside the Spring bean container. By
+ using AspectJ, standard constructs such as new
+ Person(); can be used and full security will be applied to
+ them by Acegi Security. The
+ AspectJSecurityInterceptor is still managed by
+ Spring, which creates the aspect singleton and wires it with the
+ appropriate authentication managers, access decision managers and so
+ on.
+
+ The third type is a FilterInvocation. This is
+ an object included with the Acegi Security System for Spring. It is
+ created by an included filter and simply wraps the HTTP
+ ServletRequest, ServletResponse
+ and FilterChain. The
+ FilterInvocation enables HTTP resources to be
+ secured. Developers do not usually need to understand the mechanics of
+ how this works, because they just add the filters to their
+ web.xml and let the security system do its
+ work.
+
+
+
+ Configuration Attributes
+
+ Every secure object can represent an infinite number of
+ individual requests. For example, a
+ MethodInvocation can represent the invocation of
+ any method with any arguments, whilst a
+ FilterInvocation can represent any HTTP URL.
+
+ The Acegi Security System for Spring needs to record the
+ configuration that applies to each of these possible requests. The
+ security configuration of a request to
+ BankManager.getBalance(int accountNumber) needs to
+ be very different from the security configuration of a request to
+ BankManager.approveLoan(int applicationNumber).
+ Similarly, the security configuration of a request to
+ http://some.bank.com/index.htm needs to be very
+ different from the security configuration of
+ http://some.bank.com/manage/timesheet.jsp.
+
+ To store the various security configurations associated with
+ different requests, a configuration attribute is used. At an
+ implementation level a configuration attribute is represented by the
+ ConfigAttribute interface. One concrete
+ implementation of ConfigAttribute is provided,
+ SecurityConfig, which simply stores a configuration
+ attribute as a String.
+
+ The collection of ConfigAttributes associated
+ with a particular request is held in a
+ ConfigAttributeDefinition. This concrete class is
+ simply a holder of ConfigAttributes and does
+ nothing special.
+
+ When a request is received by the security interceptor, it needs
+ to determine which configuration attributes apply. In other words, it
+ needs to find the ConfigAttributeDefinition which
+ applies to the request. This decision is handled by the
+ ObjectDefinitionSource interface. The main method
+ provided by this interface is public
+ ConfigAttributeDefinition getAttributes(Object object), with
+ the Object being the secure object. Recall the
+ secure object contains details of the request, so the
+ ObjectDefinitionSource implementation will be able
+ to extract the details it requires to lookup the relevant
+ ConfigAttributeDefinition.
+
+
+
+
+ Request Contexts
+
+
+ Contexts
+
+ Many applications require a way of sharing objects between
+ classes, but without resorting to passing them in method signatures.
+ This is commonly achieved by using a ThreadLocal.
+ The Acegi Security System for Spring uses
+ ThreadLocal functionality and introduces the
+ concept of "request contexts".
+
+ By placing an object into a request context, that object becomes
+ available to any other object on the current thread of execution. The
+ request context is not passed around as a method parameter, but is
+ held in a ThreadLocal. The Acegi Security System
+ for Spring uses the request context to pass around the authentication
+ request and response.
+
+ A request context is a concrete implementation of the
+ Context interface, which exposes a single
+ method:
+
+ public void validate() throws ContextInvalidException;
+
+ This validate() method is called to confirm
+ the Context is properly setup. An implementation
+ will typically use this method to check that the objects it holds are
+ properly setup.
+
+ The ContextHolder class makes the
+ Context available to the current thread of
+ execution using a ThreadLocal. A
+ ContextInterceptor is also provided, which is
+ intended to be chained into the bean context using
+ ProxyFactoryBean. The
+ ContextInterceptor simply calls
+ Context.validate(), which guarantees to business
+ methods that a valid Context is available from the
+ ContextHolder.
+
+
+
+ Secure Contexts
+
+ The Acegi Security System for Spring requires the
+ ContextHolder to contain a request context that
+ implements the SecureContext interface. An
+ implementation is provided named SecureContextImpl.
+ The SecureContext simply extends the
+ Context discussed above and adds a holder and
+ validation for an Authentication object.
+
+
+
+ Custom Contexts
+
+ Developers can create their own request context classes to store
+ application-specific objects. Such request context classes will need
+ to implement the Context interface. If the Acegi
+ Security System for Spring is to be used, developers must ensure any
+ custom request contexts implement the SecureContext
+ interface.
+
+
+
+
+ Security Interception
+
+
+ All Secure Objects
+
+ As described in the High Level Design section, each secure
+ object has its own security interceptor which is responsible for
+ handling each request. Handling involves a number of
+ operations:
+
+
+
+ Store the configuration attributes that are associated with
+ each secure request.
+
+
+
+ Extract the ConfigAttributeDefinition
+ that applies to the request from the relevant
+ ObjectDefinitionSource.
+
+
+
+ Obtain the Authentication object from the
+ SecureContext, which is held in the
+ ContextHolder.
+
+
+
+ Pass the Authentication object to the
+ AuthenticationManager, update the
+ ContextHolder with the response.
+
+
+
+ Pass the Authentication object, the
+ ConfigAttributeDefinition, and the secure
+ object to the AccessDecisionManager.
+
+
+
+ Pass the Authentication object, the
+ ConfigAttributeDefinition, and the secure
+ object to the RunAsManager.
+
+
+
+ If the RunAsManager returns a new
+ Authentication object, update the
+ ContextHolder with it.
+
+
+
+ Proceed with the request execution of the secure
+ object.
+
+
+
+ If the RunAsManager earlier returned a
+ new Authentication object, update the
+ ContextHolder with the
+ Authentication object that was previously
+ returned by the AuthenticationManager.
+
+
+
+ Return any result received from the secure object
+ execution.
+
+
+
+ Whilst this may seem quite involved, don't worry. Developers
+ interact with the security process by simply implementing basic
+ interfaces (such as AccessDecisionManager), which
+ are fully documented below.
+
+ The AbstractSecurityInterceptor handles the
+ majority of the flow listed above. Each secure object has its own
+ security interceptor which subclasses
+ AbstractSecurityInterceptor. Each of these secure
+ object-specific security interceptors are discussed below.
+
+
+
+ AOP Alliance (MethodInvocation) Security Interceptor
+
+ To secure MethodInvocations, developers
+ simply add a properly configured
+ MethodSecurityInterceptor into the application
+ context. Next the beans requiring security are chained into the
+ interceptor. This chaining is accomplished using Spring’s
+ ProxyFactoryBean or
+ BeanNameAutoProxyCreator, as commonly used by many
+ other parts of Spring (refer to the sample application for examples).
+ Alternatively, Acegi Security provides a
+ MethodDefinitionSourceAdvisor which may be used
+ with Spring's DefaultAdvisorAutoProxyCreator to
+ automatically chain the security interceptor in front of any beans
+ defined against the MethodSecurityInterceptor. The
+ MethodSecurityInterceptor itself is configured as
+ follows:
+
+ <bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
+ <property name="validateConfigAttributes"><value>true</value></property>
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
+ <property name="runAsManager"><ref bean="runAsManager"/></property>
+ <property name="objectDefinitionSource">
+ <value>
+ net.sf.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
+ net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
+ </value>
+ </property>
+</bean>
+
+ As shown above, the MethodSecurityInterceptor
+ is configured with a reference to an
+ AuthenticationManager,
+ AccessDecisionManager and
+ RunAsManager, which are each discussed in separate
+ sections below. The MethodSecurityInterceptor 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.
+
+ The MethodSecurityInterceptor 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. The third is via writing
+ your own ObjectDefinitionSource, although this is
+ beyond the scope of this document. Irrespective of the approach used,
+ the ObjectDefinitionSource is responsible for
+ returning a ConfigAttributeDefinition object that
+ contains all of the configuration attributes associated with a single
+ secure method.
+
+ It should be noted that the
+ MethodSecurityInterceptor.setObjectDefinitionSource()
+ method actually expects an instance of
+ MethodDefinitionSource. This is a marker interface
+ which subclasses ObjectDefinitionSource. It simply
+ denotes the ObjectDefinitionSource understands
+ MethodInvocations. In the interests of simplicity
+ we'll continue to refer to the
+ MethodDefinitionSource as an
+ ObjectDefinitionSource, as the distinction is of
+ little relevance to most users of the
+ MethodSecurityInterceptor.
+
+ 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 SecurityConfig
+ object. The SecurityConfig object is discussed in
+ the High Level Design section.
+
+ If using the Jakarta Commons Attributes approach, your bean
+ context will be configured differently:
+
+ <bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/>
+<bean id="objectDefinitionSource" class="net.sf.acegisecurity.intercept.method.MethodDefinitionAttributes">
+ <property name="attributes"><ref local="attributes"/></property>
+</bean>
+
+<bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+ <property name="validateConfigAttributes"><value>false</value></property>
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
+ <property name="runAsManager"><ref bean="runAsManager"/></property>
+ <property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/></property>
+</bean>
+
+ In addition, your source code will contain Jakarta Commons
+ Attributes tags that refer to a concrete implementation of
+ ConfigAttribute. The following example uses the
+ SecurityConfig implementation to represent the
+ configuration attributes, and results in the same security
+ configuration as provided by the property editor approach
+ above:
+
+ 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);
+}
+
+ You might have noticed the
+ validateConfigAttributes property in the above
+ MethodSecurityInterceptor examples. When set to
+ true (the default), at startup time the
+ MethodSecurityInterceptor will evaluate if the
+ provided configuration attributes are valid. It does this by checking
+ each configuration attribute can be processed by either the
+ AccessDecisionManager or the
+ RunAsManager. 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
+ validateConfigAttributes to
+ false.
+
+
+
+ AspectJ (JoinPoint) Security Interceptor
+
+ 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.
+
+ The AspectJ interceptor is named
+ AspectJSecurityInterceptor. Unlike the AOP Alliance
+ security interceptor, which relies on the Spring application context
+ to weave in the security interceptor via proxying, the
+ AspectJSecurityInterceptor is weaved in via the
+ AspectJ compiler. It would not be uncommon to use both types of
+ security interceptors in the same application, with
+ AspectJSecurityInterceptor being used for domain
+ object instance security and the AOP Alliance
+ MethodSecurityInterceptor being used for services
+ layer security.
+
+ Let's first consider how the
+ AspectJSecurityInterceptor is configured in the
+ Spring application context:
+
+ <bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor">
+ <property name="validateConfigAttributes"><value>true</value></property>
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
+ <property name="runAsManager"><ref bean="runAsManager"/></property>
+ <property name="objectDefinitionSource">
+ <value>
+ net.sf.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
+ net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
+ </value>
+ </property>
+</bean>
+
+ As you can see, aside from the class name, the
+ AspectJSecurityInterceptor is exactly the same as
+ the AOP Alliance security interceptor. Indeed the two interceptors can
+ share the same objectDefinitionSource, as the
+ ObjectDefinitionSource works with
+ java.lang.reflect.Methods rather than an AOP
+ library-specific class. Of course, your access decisions have access
+ to the relevant AOP library-specific invocation (ie
+ MethodInvocation or JoinPoint)
+ and as such can consider a range of addition criteria when making
+ access decisions (such as method arguments).
+
+ Next you'll need to define an AspectJ aspect.
+ For example:
+
+ package net.sf.acegisecurity.samples.aspectj;
+
+import net.sf.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor;
+import net.sf.acegisecurity.intercept.method.aspectj.AspectJCallback;
+import org.springframework.beans.factory.InitializingBean;
+
+public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
+
+ private AspectJSecurityInterceptor securityInterceptor;
+
+ pointcut domainObjectInstanceExecution(): target(PersistableEntity)
+ && execution(public * *(..)) && !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");
+ }
+}
+
+ In the above example, the security interceptor will be applied
+ to every instance of PersistableEntity, which is an
+ abstract class not shown (you can use any other class or
+ pointcut expression you like). For those curious,
+ AspectJCallback is needed because the
+ proceed(); statement has special meaning only
+ within an around() body. The
+ AspectJSecurityInterceptor calls this anonymous
+ AspectJCallback class when it wants the target
+ object to continue.
+
+ You will need to configure Spring to load the aspect and wire it
+ with the AspectJSecurityInterceptor. A bean
+ declaration which achieves this is shown below:
+
+ <bean id="domainObjectInstanceSecurityAspect"
+ class="net.sf.acegisecurity.samples.aspectj.DomainObjectInstanceSecurityAspect"
+ factory-method="aspectOf">
+ <property name="securityInterceptor"><ref bean="aspectJSecurityInterceptor"/></property>
+</bean>
+
+ That's it! Now you can create your beans from anywhere within
+ your application, using whatever means you think fit (eg new
+ Person();) and they will have the security interceptor
+ applied.
+
+
+
+ FilterInvocation Security Interceptor
+
+ To secure FilterInvocations, developers need
+ to add a filter to their web.xml that delegates to
+ the SecurityEnforcementFilter. A typical
+ configuration example is provided below: <filter>
+ <filter-name>Acegi HTTP Request Security Filter</filter-name>
+ <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
+ <init-param>
+ <param-name>targetClass</param-name>
+ <param-value>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value>
+ </init-param>
+</filter>
+
+<filter-mapping>
+ <filter-name>Acegi HTTP Request Security Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>
+
+ Notice that the filter is actually a
+ FilterToBeanProxy. Most of the filters used by the
+ Acegi Security System for Spring use this class. Refer to the Filters
+ section to learn more about this bean.
+
+ In the application context you will need to configure three
+ beans:
+
+ <bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
+ <property name="filterSecurityInterceptor"><ref bean="filterInvocationInterceptor"/></property>
+ <property name="authenticationEntryPoint"><ref bean="authenticationEntryPoint"/></property>
+</bean>
+
+<bean id="authenticationEntryPoint" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
+ <property name="loginFormUrl"><value>/acegilogin.jsp</value></property>
+ <property name="forceHttps"><value>false</value></property>
+</bean>
+
+<bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
+ <property name="runAsManager"><ref bean="runAsManager"/></property>
+ <property name="objectDefinitionSource">
+ <value>
+ CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
+ \A/secure/super/.*\Z=ROLE_WE_DONT_HAVE
+ \A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_TELLER
+ </value>
+ </property>
+</bean>
+
+ The AuthenticationEntryPoint 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 the Acegi Security System for
+ Spring: AuthenticationProcessingFilterEntryPoint
+ for commencing a form-based authentication,
+ BasicProcessingFilterEntryPoint for commencing a
+ Http Basic authentication process, and
+ CasProcessingFilterEntryPoint for commencing a Yale
+ Central Authentication Service (CAS) login. The
+ AuthenticationProcessingFilterEntryPoint and
+ CasProcessingFilterEntryPoint have optional
+ properties related to forcing the use of HTTPS, so please refer to the
+ JavaDocs if you require this.
+
+ The PortMapper provides information on which
+ HTTPS ports correspond to which HTTP ports. This is used by the
+ AuthenticationProcessingFilterEntryPoint and
+ several other beans. The default implementation,
+ PortMapperImpl, knows the common HTTP ports 80 and
+ 8080 map to HTTPS ports 443 and 8443 respectively. You can customise
+ this mapping if desired.
+
+ The SecurityEnforcementFilter primarily
+ provides session management support and initiates authentication when
+ required. It delegates actual FilterInvocation
+ security decisions to the configured
+ FilterSecurityInterceptor.
+
+ Like any other security interceptor, the
+ FilterSecurityInterceptor requires a reference to
+ an AuthenticationManager,
+ AccessDecisionManager and
+ RunAsManager, which are each discussed in separate
+ sections below. The FilterSecurityInterceptor 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.
+
+ The FilterSecurityInterceptor 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
+ ObjectDefinitionSource, although this is beyond the
+ scope of this document. Irrespective of the approach used, the
+ ObjectDefinitionSource is responsible for returning
+ a ConfigAttributeDefinition object that contains
+ all of the configuration attributes associated with a single secure
+ HTTP URL.
+
+ It should be noted that the
+ FilterSecurityInterceptor.setObjectDefinitionSource()
+ method actually expects an instance of
+ FilterInvocationDefinitionSource. This is a marker
+ interface which subclasses ObjectDefinitionSource.
+ It simply denotes the ObjectDefinitionSource
+ understands FilterInvocations. In the interests of
+ simplicity we'll continue to refer to the
+ FilterInvocationDefinitionSource as an
+ ObjectDefinitionSource, as the distinction is of
+ little relevance to most users of the
+ FilterSecurityInterceptor.
+
+ 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 SecurityConfig object. The
+ SecurityConfig object is discussed in the High
+ Level Design section. The ObjectDefinitionSource
+ created by the property editor,
+ FilterInvocationDefinitionSource, matches
+ configuration attributes against FilterInvocations
+ 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
+ PATTERN_TYPE_APACHE_ANT 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:
+
+ <bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
+ <property name="runAsManager"><ref bean="runAsManager"/></property>
+ <property name="objectDefinitionSource">
+ <value>
+ CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
+ PATTERN_TYPE_APACHE_ANT
+ /secure/super/**=ROLE_WE_DONT_HAVE
+ /secure/**=ROLE_SUPERVISOR,ROLE_TELLER
+ </value>
+ </property>
+</bean>
+
+ 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 /secure/super/
+ pattern appears higher than the less specific
+ /secure/ pattern. If they were reversed, the
+ /secure/ pattern would always match and the
+ /secure/super/ pattern would never be
+ evaluated.
+
+ The special keyword
+ CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON causes
+ the FilterInvocationDefinitionSource 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
+ CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON and
+ write each expression assuming lowercase.
+
+ As with other security interceptors, the
+ validateConfigAttributes property is observed. When
+ set to true (the default), at startup time the
+ FilterSecurityInterceptor will evaluate if the
+ provided configuration attributes are valid. It does this by checking
+ each configuration attribute can be processed by either the
+ AccessDecisionManager or the
+ RunAsManager. If neither of these can process a
+ given configuration attribute, an exception is thrown.
+
+
+
+
+ Authentication
+
+
+ Authentication Requests
+
+ Authentication requires a way for client code to present its
+ security identification to the Acegi Security System for Spring. This
+ is the role of the Authentication interface. The
+ Authentication interface holds three important
+ objects: the principal (the identity of the caller), the credentials
+ (the proof of the identity of the caller, such as a password), and the
+ authorities that have been granted to the principal. The principal and
+ its credentials are populated by the client code, whilst the granted
+ authorities are populated by the
+ AuthenticationManager. The Acegi Security System
+ for Spring includes several concrete Authentication
+ implementations:
+
+
+
+ UsernamePasswordAuthenticationToken
+ allows a username and password to be presented as the principal
+ and credentials respectively. It is also what is created by the
+ HTTP Session Authentication system.
+
+
+
+ TestingAuthenticationToken facilitates
+ unit testing by automatically being considered an authenticated
+ object by its associated
+ AuthenticationProvider.
+
+
+
+ RunAsUserToken is used by the default
+ run-as authentication replacement implementation. This is
+ discussed further in the Run-As Authentication Replacement
+ section.
+
+
+
+ CasAuthenticationToken is used to
+ represent a successful Yale Central Authentication Service (CAS)
+ authentication. This is discussed further in the CAS
+ section.
+
+
+
+ PrincipalAcegiUserToken and
+ JettyAcegiUserToken implement
+ AuthByAdapter (a subclass of
+ Authentication) and are used whenever
+ authentication is completed by Acegi Security System for Spring
+ container adapters. This is discussed further in the Container
+ Adapters section.
+
+
+
+ The authorities granted to a principal are represented by the
+ GrantedAuthority interface. The
+ GrantedAuthority interface is discussed at length
+ in the Authorization section.
+
+
+
+ Authentication Manager
+
+ As discussed in the Security Interception section, the
+ AbstractSecurityInterceptor extracts the
+ Authentication object from the
+ SecureContext in the
+ ContextHolder. This is then passed to an
+ AuthenticationManager. The
+ AuthenticationManager interface is very
+ simple:
+
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException;
+
+ Implementations of AuthenticationManager are
+ required to throw an AuthenticationException should
+ authentication fail, or return a fully populated
+ Authentication object. In particular, the returned
+ Authentication object should contain an array of
+ GrantedAuthority objects. The
+ SecurityInterceptor places the populated
+ Authentication object back in the
+ SecureContext in the
+ ContextHolder, overwriting the original
+ Authentication object.
+
+ The AuthenticationException has a number of
+ subclasses. The most important are
+ BadCredentialsException (an incorrect principal or
+ credentials), DisabledException and
+ LockedException. The latter two exceptions indicate
+ the principal was found, but the credentials were not checked and
+ authentication is denied. An
+ AuthenticationServiceException is also provided,
+ which indicates the authentication system could not process the
+ request (eg a database was unavailable).
+
+
+
+ Provider-Based Authentication
+
+ Whilst the basic Authentication and
+ AuthenticationManager interfaces enable users to
+ develop their own authentication systems, users should consider using
+ the provider-based authentication packages provided by the Acegi
+ Security System for Spring. The key class,
+ ProviderManager, is configured via the bean context
+ with a list of AuthenticationProviders:
+
+ <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
+ <property name="providers">
+ <list>
+ <ref bean="daoAuthenticationProvider"/>
+ <ref bean="someOtherAuthenticationProvider"/>
+ </list>
+ </property>
+</bean>
+
+ ProviderManager calls a series of registered
+ AuthenticationProvider implementations, until one
+ is found that indicates it is able to authenticate a given
+ Authentication class. When the first compatible
+ AuthenticationProvider is located, it is passed the
+ authentication request. The AuthenticationProvider
+ will then either throw an AuthenticationException
+ or return a fully populated Authentication
+ object.
+
+ Note the ProviderManager may throw a
+ ProviderNotFoundException (a subclass of
+ AuthenticationException) if it none of the
+ registered AuthenticationProviders can validate the
+ Authentication object.
+
+ Several AuthenticationProvider
+ implementations are provided with the Acegi Security System for
+ Spring:
+
+
+
+ TestingAuthenticationProvider is able
+ to authenticate a TestingAuthenticationToken.
+ The limit of its authentication is simply to treat whatever is
+ contained in the TestingAuthenticationToken
+ as valid. This makes it ideal for use during unit testing, as
+ you can create an Authentication object with
+ precisely the GrantedAuthority objects
+ required for calling a given method. You definitely would not
+ register this AuthenticationProvider on a
+ production system.
+
+
+
+ DaoAuthenticationProvider is able to
+ authenticate a
+ UsernamePasswordAuthenticationToken by
+ accessing an authentication respository via a data access
+ object. This is discussed further below, as it is the main way
+ authentication is initially handled.
+
+
+
+ RunAsImplAuthenticationToken is able to
+ authenticate a RunAsUserToken. This is
+ discussed further in the Run-As Authentication Replacement
+ section. You would not register this
+ AuthenticationProvider if you were not using
+ run-as replacement.
+
+
+
+ AuthByAdapterProvider is able to
+ authenticate any AuthByAdapter (a subclass of
+ Authentication used with container adapters).
+ This is discussed further in the Container Adapters section. You
+ would not register this
+ AuthenticationProvider if you were not using
+ container adapters.
+
+
+
+ CasAuthenticationProvider is able to
+ authenticate Yale Central Authentication Service (CAS) tickets.
+ This is discussed further in the CAS Single Sign On
+ section.
+
+
+
+ JaasAuthenticationProvider is able to
+ delegate authentication requests to a JAAS
+ LoginModule. This is discussed further
+ below.
+
+
+
+
+
+ Data Access Object Authentication Provider
+
+ The Acegi Security System for Spring includes a
+ production-quality AuthenticationProvider
+ implementation called DaoAuthenticationProvider.
+ This authentication provider is able to authenticate a
+ UsernamePasswordAuthenticationToken by obtaining
+ authentication details from a data access object configured at bean
+ creation time:
+
+ <bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
+ <property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
+ <property name="saltSource"><ref bean="saltSource"/></property>
+ <property name="passwordEncoder"><ref bean="passwordEncoder"/></property>
+</bean>
+
+ The PasswordEncoder and
+ SaltSource are optional. A
+ PasswordEncoder provides encoding and decoding of
+ passwords obtained from the authentication repository. A
+ SaltSource enables the passwords to be populated
+ with a "salt", which enhances the security of the passwords in the
+ authentication repository. PasswordEncoder
+ implementations are provided with the Acegi Security System for Spring
+ covering MD5, SHA and cleartext encodings. Two
+ SaltSource implementations are also provided:
+ SystemWideSaltSource which encodes all passwords
+ with the same salt, and ReflectionSaltSource, which
+ inspects a given property of the returned
+ UserDetails object to obtain the salt. Please refer
+ to the JavaDocs for further details on these optional features.
+
+ In addition to the properties above, the
+ DaoAuthenticationProvider supports optional caching
+ of UserDetails objects. The
+ UserCache interface enables the
+ DaoAuthenticationProvider to place a
+ UserDetails object into the cache, and retrieve it
+ from the cache upon subsequent authentication attempts for the same
+ username. By default the DaoAuthenticationProvider
+ uses the NullUserCache, which performs no caching.
+ A usable caching implementation is also provided,
+ EhCacheBasedUserCache, which is configured as
+ follows:
+
+ <bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
+ <property name="authenticationDao"><ref bean="authenticationDao"/></property>
+ <property name="userCache"><ref bean="userCache"/></property>
+</bean>
+
+<bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
+ <property name="minutesToIdle"><value>5</value></property>
+</bean>
+
+ For a class to be able to provide the
+ DaoAuthenticationProvider with access to an
+ authentication repository, it must implement the
+ AuthenticationDao interface:
+
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;
+
+ The UserDetails 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. A concrete implementation,
+ User, is also provided. Acegi Security users will
+ need to decide when writing their AuthenticationDao
+ what type of UserDetails to return. In most cases
+ User will be used directly or subclassed, although
+ special circumstances (such as object relational mappers) may require
+ users to write their own UserDetails implementation
+ from scratch.
+
+ Given AuthenticationDao is so simple to
+ implement, it should be easy for users to retrieve authentication
+ information using a persistence strategy of their choice.
+
+ A design decision was made not to support account locking in the
+ DaoAuthenticationProvider, as doing so would have
+ increased the complexity of the AuthenticationDao
+ 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.
+
+ DaoAuthenticationProvider returns an
+ Authentication object which in turn has its
+ principal property set. The principal will be
+ either a String (which is essentially the username)
+ or a UserDetails object (which was looked up from
+ the AuthenticationDao). By default the
+ UserDetails 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 Strings (as was the case for releases
+ prior to Acegi Security 0.6), you should set the
+ DaoAuthenticationProvider.forcePrincipalAsString
+ property to true in your application
+ context.
+
+
+
+ Event Publishing
+
+ The DaoAuthenticationProvider automatically
+ obtains the ApplicationContext it is running in at
+ startup time. This allows the provider to publish events through the
+ standard Spring event framework. Three types of event messages are
+ published:
+
+
+
+ AuthenticationSuccessEvent is published
+ when an authentication request is successful.
+
+
+
+ AuthenticationFailureDisabledEvent is
+ published when an authentication request is unsuccessful because
+ the returned UserDetails is disabled. This is
+ normally the case when an account is locked.
+
+
+
+ AuthenticationFailureUsernameNotFoundEvent
+ is published when an authentication request is unsuccessful
+ because the AuthenticationDao could not locate
+ the UserDetails.
+
+
+
+ AuthenticationFailurePasswordEvent is
+ published when an authentication request is unsuccessful because
+ the presented password did not match that in the
+ UserDetails.
+
+
+
+ Each event contains two objects: the
+ Authentication object that represented the
+ authentication request, and the UserDetails object
+ that was found in response to the authentication request (clearly the
+ latter will be a dummy object in the case of
+ AuthenticationFailureUsernameNotFoundEvent). The
+ Authentication interface provides a
+ getDetails() method which often includes
+ information that event consumers may find useful (eg the TCP/IP
+ address that the authentication request originated from).
+
+ As per standard Spring event handling, you can receive these
+ events by adding a bean to the application context which implements
+ the ApplicationListener interface. Included with
+ Acegi Security is a LoggerListener class which
+ receives these events and publishes their details to Commons Logging.
+ Refer to the JavaDocs for LoggerListener for
+ details on the logging priorities used for different message
+ types.
+
+ This event publishing system enables you to implement account
+ locking and record authentication event history. This might be of
+ interest to application users, who can be advised of the times and
+ source IP address of all unsuccessful password attempts (and account
+ lockouts) since their last successful login. Such capabilities are
+ simple to implement and greatly improve the security of your
+ application.
+
+
+
+ In-Memory Authentication
+
+ Whilst it is easy to use the
+ DaoAuthenticationProvider and create a custom
+ AuthenticationDao implementation that extracts
+ information from a persistence engine of choice, many applications do
+ not require such complexity. One alternative is to configure an
+ authentication repository in the application context itself using the
+ InMemoryDaoImpl:
+
+ <bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
+ <property name="userMap">
+ <value>
+ marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
+ dianne=emu,ROLE_TELLER
+ scott=wombat,ROLE_TELLER
+ peter=opal,disabled,ROLE_TELLER
+ </value>
+ </property>
+</bean>
+
+ The userMap property contains each of the
+ usernames, passwords, a list of granted authorities and an optional
+ enabled/disabled keyword. Commas 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
+ enabled and disabled keywords
+ (case insensitive) may appear in the second or any subsequent token.
+ Any remaining tokens are treated as granted authorities, which are
+ created as GrantedAuthorityImpl objects (refer to
+ the Authorization section for further discussion on granted
+ authorities). 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.
+
+
+
+ JDBC Authentication
+
+ The Acegi Security System for Spring also includes an
+ authentication provider that can obtain authentication information
+ from a JDBC data source. The typical configuration for the
+ JdbcDaoImpl is shown below:
+
+ <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property>
+ <property name="url"><value>jdbc:hsqldb:hsql://localhost:9001</value></property>
+ <property name="username"><value>sa</value></property>
+ <property name="password"><value></value></property>
+</bean>
+
+<bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
+ <property name="dataSource"><ref bean="dataSource"/></property>
+</bean>
+
+ You can use different relational database management systems by
+ modifying the DriverManagerDataSource shown above.
+ Irrespective of the database used, a standard schema must be used as
+ indicated in dbinit.txt.
+
+ If you default schema is unsuitable for your needs,
+ JdbcDaoImpl provides two properties that allow
+ customisation of the SQL statements. You may also subclass the
+ JdbcDaoImpl if further customisation is necessary.
+ Please refer to the JavaDocs for details.
+
+ The Acegi Security System for Spring ships with a Hypersonic SQL
+ instance that has the required authentication information and sample
+ data already populated. To use this server, simply execute the
+ server.bat or server.sh script
+ included in the distribution. This will load a new database server
+ instance that will service requests made to the URL indicated in the
+ bean context configuration shown above.
+
+
+
+ JAAS Authentication
+
+ 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.
+
+ 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.
+
+
+ JaasAuthenticationProvider
+
+ The JaasAuthenticationProvider attempts to
+ authenticate a user’s principal and credentials through JAAS.
+
+ Let’s assume we have a JAAS login configuration file,
+ /WEB-INF/login.conf, with the following
+ contents:
+
+ JAASTest {
+ sample.SampleLoginModule required;
+};
+
+ Like all Acegi Security beans, the
+ JaasAuthenticationProvider is configured via the
+ application context. The following definitions would correspond to
+ the above JAAS login configuration file:
+
+ <bean id="jaasAuthenticationProvider" class="net.sf.acegisecurity.providers.jaas.JaasAuthenticationProvider">
+ <property name="loginConfig">
+ <value>/WEB-INF/login.conf</value>
+ </property>
+ <property name="loginContextName">
+ <value>JAASTest</value>
+ </property>
+ <property name="callbackHandlers">
+ <list>
+ <bean class="net.sf.acegisecurity.providers.jaas.JaasNameCallbackHandler"/>
+ <bean class="net.sf.acegisecurity.providers.jaas.JaasPasswordCallbackHandler"/>
+ </list>
+ </property>
+ <property name="authorityGranters">
+ <list>
+ <bean class="net.sf.acegisecurity.providers.jaas.TestAuthorityGranter"/>
+ </list>
+ </property>
+</bean>
+
+ The CallbackHandlers and
+ AuthorityGranters are discussed below.
+
+
+
+ Callbacks
+
+ Most JAAS LoginModules require a callback
+ of some sort. These callbacks are usually used to obtain the
+ username and password from the user. In an Acegi Security
+ deployment, Acegi Security is responsible for this user interaction
+ (typically via a reference to a
+ ContextHolder-managed
+ Authentication object). The JAAS package for
+ Acegi Security provides two default callback handlers,
+ JaasNameCallbackHandler and
+ JaasPasswordCallbackHandler. Each of these
+ callback handlers implement
+ JaasAuthenticationCallbackHandler. In most cases
+ these callback handlers can simply be used without understanding the
+ internal mechanics. For those needing full control over the callback
+ behavior, internally JaasAutheticationProvider
+ wraps these JaasAuthenticationCallbackHandlers
+ with an InternalCallbackHandler. The
+ InternalCallbackHandler is the class that
+ actually implements JAAS’ normal CallbackHandler
+ interface. Any time that the JAAS LoginModule is
+ used, it is passed a list of application context configured
+ InternalCallbackHandlers. If the
+ LoginModule requests a callback against the
+ InternalCallbackHandlers, the callback is in-turn
+ passed to the JaasAuthenticationCallbackHandlers
+ being wrapped.
+
+
+
+ AuthorityGranters
+
+ JAAS works with principals. Even “roles” are represented as
+ principals in JAAS. Acegi Security, on the other hand, works with
+ Authentication objects. Each
+ Authentication object contains a single
+ principal, and multiple GrantedAuthority[]s. To
+ facilitate mapping between these different concepts, the Acegi
+ Security JAAS package includes an
+ AuthorityGranter interface. An
+ AuthorityGranter is responsible for inspecting a
+ JAAS principal and returning a String. The
+ JaasAuthenticationProvider then creates a
+ JaasGrantedAuthority (which implements Acegi
+ Security’s GrantedAuthority interface) containing
+ both the AuthorityGranter-returned
+ String and the JAAS principal that the
+ AuthorityGranter was passed. The
+ JaasAuthenticationProvider obtains the JAAS
+ principals by firstly successfully authenticating the user’s
+ credentials using the JAAS LoginModule, and then
+ accessing the LoginContext it returns. A call to
+ LoginContext.getSubject().getPrincipals() is
+ made, with each resulting principal passed to each
+ AuthorityGranter defined against the
+ JaasAuthenticationProvider.setAuthorityGranters(List)
+ property. Acegi Security does not include any production
+ AuthorityGranters given every JAAS principal has
+ an implementation-specific meaning. However, there is a
+ TestAuthorityGranter in the unit tests that
+ demonstrates a simple AuthorityGranter
+ implementation.
+
+
+
+
+ Authentication Recommendations
+
+ With the heavy use of interfaces throughout the authentication
+ system (Authentication,
+ AuthenticationManager,
+ AuthenticationProvider and
+ AuthenticationDao) it might be confusing to a new
+ user to know which part of the authentication system to customize. In
+ general, the following is recommended:
+
+
+
+ Use the
+ UsernamePasswordAuthenticationToken
+ implementation where possible.
+
+
+
+ If you simply need to implement a new authentication
+ repository (eg to obtain user details from your application’s
+ existing database), use the
+ DaoAuthenticationProvider along with the
+ AuthenticationDao. It is the fastest and safest
+ way to integrate an external database.
+
+
+
+ If you're using Container Adapters or a
+ RunAsManager that replaces the
+ Authentication object, ensure you have
+ registered the AuthByAdapterProvider and
+ RunAsManagerImplProvider respectively with your
+ ProviderManager.
+
+
+
+ Never enable the
+ TestingAuthenticationProvider on a production
+ system. Doing so will allow any client to simply present a
+ TestingAuthenticationToken and obtain whatever
+ access they request.
+
+
+
+ Adding a new AuthenticationProvider is
+ sufficient to support most custom authentication requirements.
+ Only unusual requirements would require the
+ ProviderManager to be replaced with a different
+ AuthenticationManager.
+
+
+
+
+
+
+ Authorization
+
+
+ Granted Authorities
+
+ As briefly mentioned in the Authentication section, all
+ Authentication implementations are required to
+ store an array of GrantedAuthority objects. These
+ represent the authorities that have been granted to the principal. The
+ GrantedAuthority objects are inserted into the
+ Authentication object by the
+ AuthenticationManager and are later read by
+ AccessDecisionManagers when making authorization
+ decisions.
+
+ GrantedAuthority is an interface with only
+ one method:
+
+ public String getAuthority();
+
+ This method allows AccessDecisionManagers to
+ obtain a precise String representation of the
+ GrantedAuthority. By returning a representation as
+ a String, a GrantedAuthority can
+ be easily "read" by most AccessDecisionManagers. If
+ a GrantedAuthority cannot be precisely represented
+ as a String, the
+ GrantedAuthority is considered "complex" and
+ getAuthority() must return
+ null.
+
+ An example of a "complex" GrantedAuthority
+ would be an implementation that stores a list of operations and
+ authority thresholds that apply to different customer account numbers.
+ Representing this complex GrantedAuthority as a
+ String would be quite complex, and as a result the
+ getAuthority() method should return
+ null. This will indicate to any
+ AccessDecisionManager that it will need to
+ specifically support the GrantedAuthority
+ implementation in order to understand its contents.
+
+ The Acegi Security System for Spring includes one concrete
+ GrantedAuthority implementation,
+ GrantedAuthorityImpl. This allows any
+ user-specified String to be converted into a
+ GrantedAuthority. All
+ AuthenticationProviders included with the security
+ architecture use GrantedAuthorityImpl to populate
+ the Authentication object.
+
+
+
+ Access Decision Managers
+
+ The AccessDecisionManager is called by the
+ AbstractSecurityInterceptor and is responsible for
+ making final access control decisions. The
+ AccessDecisionManager interface contains three
+ methods:
+
+ public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config) throws AccessDeniedException;
+public boolean supports(ConfigAttribute attribute);
+public boolean supports(Class clazz);
+
+ As can be seen from the first method, the
+ AccessDecisionManager is passed via method
+ parameters all information that is likely to be of value in assessing
+ an authorization decision. In particular, passing the secure
+ Object enables those arguments contained in the
+ actual secure object invocation to be inspected. For example, let's
+ assume the secure object was a MethodInvocation. It
+ would be easy to query the MethodInvocation for any
+ Customer argument, and then implement some sort of
+ security logic in the AccessDecisionManager to
+ ensure the principal is permitted to operate on that customer.
+ Implementations are expected to throw an
+ AccessDeniedException if access is denied.
+
+ The supports(ConfigAttribute) method is
+ called by the AbstractSecurityInterceptor at
+ startup time to determine if the
+ AccessDecisionManager can process the passed
+ ConfigAttribute. The
+ supports(Class) method is called by a security
+ interceptor implementation to ensure the configured
+ AccessDecisionManager supports the type of secure
+ object that the security interceptor will present.
+
+
+
+ Voting Decision Manager
+
+ Whilst users can implement their own
+ AccessDecisionManager to control all aspects of
+ authorization, the Acegi Security System for Spring includes several
+ AccessDecisionManager implementations that are
+ based on voting. Using this approach, a series of
+ AccessDecisionVoter implementations are polled on
+ an authorization decision. The
+ AccessDecisionManager then decides whether or not
+ to throw an AccessDeniedException based on its
+ assessment of the votes.
+
+ The AccessDecisionVoter interface has three
+ methods:
+
+ public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);
+public boolean supports(ConfigAttribute attribute);
+public boolean supports(Class clazz);
+
+ Concrete implementations return an int, with
+ possible values being reflected in the
+ AccessDecisionVoter static fields
+ ACCESS_ABSTAIN, ACCESS_DENIED
+ and ACCESS_GRANTED. A voting implementation will
+ return ACCESS_ABSTAIN if it has no opinion on an
+ authorization decision. If it does have an opinion, it must return
+ either ACCESS_DENIED or
+ ACCESS_GRANTED.
+
+ There are three concrete
+ AccessDecisionManagers provided with the Acegi
+ Security System for Spring that tally the votes. The
+ ConsensusBased 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 AffirmativeBased
+ implementation will grant access if one or more
+ ACCESS_GRANTED votes were received (ie a deny vote
+ will be ignored, provided there was at least one grant vote). Like the
+ ConsensusBased implementation, there is a parameter
+ that controls the behavior if all voters abstain. The
+ UnanimousBased provider expects unanimous
+ ACCESS_GRANTED votes in order to grant access,
+ ignoring abstains. It will deny access if there is any
+ ACCESS_DENIED vote. Like the other implementations,
+ there is a parameter that controls the behaviour if all voters
+ abstain.
+
+ It is possible to implement a custom
+ AccessDecisionManager that tallies votes
+ differently. For example, votes from a particular
+ AccessDecisionVoter might receive additional
+ weighting, whilst a deny vote from a particular voter may have a veto
+ effect.
+
+ There is one concrete AccessDecisionVoter
+ implementation provided with the Acegi Security System for Spring. The
+ RoleVoter class will vote if any ConfigAttribute
+ begins with ROLE_. It will vote to grant access if
+ there is a GrantedAuthority which returns a
+ String representation (via the
+ getAuthority() method) exactly equal to one or more
+ ConfigAttributes starting with
+ ROLE_. If there is no exact match of any
+ ConfigAttribute starting with
+ ROLE_, the RoleVoter will vote
+ to deny access. If no ConfigAttribute begins with
+ ROLE_, the voter will abstain.
+ RoleVoter is case sensitive on comparisons as well
+ as the ROLE_ prefix.
+
+ It is possible to implement a custom
+ AccessDecisionVoter. Several examples are provided
+ in the Acegi Security System for Spring unit tests, including
+ ContactSecurityVoter and
+ DenyVoter. The
+ ContactSecurityVoter abstains from voting decisions
+ where a CONTACT_OWNED_BY_CURRENT_USER
+ ConfigAttribute is not found. If voting, it queries
+ the MethodInvocation to extract the owner of the
+ Contact object that is subject of the method call.
+ It votes to grant access if the Contact owner
+ matches the principal presented in the
+ Authentication object. It could have just as easily
+ compared the Contact owner with some
+ GrantedAuthority the
+ Authentication object presented. All of this is
+ achieved with relatively few lines of code and demonstrates the
+ flexibility of the authorization model.
+
+
+
+ Authorization Tag Library
+
+ The Acegi Security System for Spring comes bundled with a JSP
+ tag library that eases JSP writing. The tag library is known as
+ authz.
+
+ This library allows you to easy develop JSP pages which
+ reference the security environment. For example,
+ authz allows you to determine if a principal holds
+ a particular granted authority, holds a group of granted authorities,
+ or does not hold a given granted authority.
+
+
+ Usage
+
+ The following JSP fragment illustrates how to use the
+ authz taglib:
+
+ <authz:authorize ifAllGranted="ROLE_SUPERVISOR">
+ <td>
+ <A HREF="del.htm?id=<c:out value="${contact.id}"/>">Del</A>
+ </td>
+</authz:authorize>
+
+ This code was copied from the Contacts sample
+ application.
+
+ What this code says is: if the principal has been granted
+ ROLE_SUPERVISOR, allow the tag's body to be output.
+
+
+
+ Installation
+
+ Installation is a simple matter. Simply copy the
+ acegi-security-taglib.jar file into your
+ application's WEB-INF/lib folder. The tag library
+ includes it's TLD, which makes it easier to work with JSP 1.2+
+ containers.
+
+ If you are using a JSP 1.1 container, you will need to declare
+ the JSP tag library in your application's web.xml
+ file, with code such as this:
+
+ <taglib>
+ <taglib-uri>http://acegisecurity.sf.net/authz</taglib-uri>
+ <taglib-location>/WEB-INF/authz.tld</taglib-location>
+</taglib>
+
+ For JSP 1.1 containers you will also need to extract the
+ authz.tld file from the
+ acegi-security-taglib.jar file and put it into
+ your application's WEB-INF/lib folder. Use a
+ regular Zip tool, or Java's JAR utility.
+
+
+
+ Reference
+
+ The authz:authorize tag declares the
+ following attributes:
+
+
+
+ ifAllGranted: All the listed roles
+ must be granted for the tag to output its body.
+
+
+
+ ifAnyGranted: Any of the listed roles
+ must be granted for the tag to output its body.
+
+
+
+ ifNotGranted: None of the listed
+ roles must be granted for the tag to output its body.
+
+
+
+ You'll note that in each attribute you can list multiple
+ roles. Simply separate the roles using a comma. The
+ authorize tag ignores whitespace in
+ attributes.
+
+ 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 ifAllGranted="ROLE_SUPERVISOR", followed by an
+ ifNotGranted="ROLE_SUPERVISOR", or you'll be
+ surprised to never see the tag's body.
+
+ By requiring all attributes to return true, the authorize tag
+ allows you to create more complex authorization scenarios. For
+ example, you could declare an
+ ifAllGranted="ROLE_SUPERVISOR" and an
+ ifNotGranted="ROLE_NEWBIE_SUPERVISOR" in the same
+ tag, in order to prevent new supervisors from seeing the tag body.
+ However it would no doubt be simpler to use
+ ifAllGranted="ROLE_EXPERIENCED_SUPERVISOR" rather
+ than inserting NOT conditions into your design.
+
+ One last item: the tag verifies the authorizations in a
+ specific order: first ifNotGranted, then
+ ifAllGranted, and finally,
+ ifAnyGranted.
+
+
+
+
+ Authorization Recommendations
+
+ Given there are several ways to achieve similar authorization
+ outcomes in the Acegi Security System for Spring, the following
+ general recommendations are made:
+
+
+
+ Grant authorities using
+ GrantedAuthorityImpl where possible. Because it
+ is already supported by the Acegi Security System for Spring, you
+ avoid the need to create custom
+ AuthenticationManager or
+ AuthenticationProvider implementations simply
+ to populate the Authentication object with a
+ custom GrantedAuthority.
+
+
+
+ Writing an AccessDecisionVoter
+ implementation and using either ConsensusBased,
+ AffirmativeBased or
+ UnanimousBased as the
+ AccessDecisionManager may be the best approach
+ to implementing your custom access decision rules.
+
+
+
+
+
+
+ Run-As Authentication Replacement
+
+
+ Purpose
+
+ The AbstractSecurityInterceptor is able to
+ temporarily replace the Authentication object in
+ the SecureContext and
+ ContextHolder during the
+ SecurityInterceptorCallback. This only occurs if
+ the original Authentication object was successfully
+ processed by the AuthenticationManager and
+ AccessDecisionManager. The
+ RunAsManager will indicate the replacement
+ Authentication object, if any, that should be used
+ during the SecurityInterceptorCallback.
+
+ By temporarily replacing the Authentication
+ object during a SecurityInterceptorCallback, 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
+ GrantedAuthority objects.
+
+
+
+ Usage
+
+ A RunAsManager interface is provided by the
+ Acegi Security System for Spring:
+
+ public Authentication buildRunAs(Authentication authentication, Object object, ConfigAttributeDefinition config);
+public boolean supports(ConfigAttribute attribute);
+public boolean supports(Class clazz);
+
+ The first method returns the Authentication
+ object that should replace the existing
+ Authentication object for the duration of the
+ method invocation. If the method returns null, it
+ indicates no replacement should be made. The second method is used by
+ the AbstractSecurityInterceptor as part of its
+ startup validation of configuration attributes. The
+ supports(Class) method is called by a security
+ interceptor implementation to ensure the configured
+ RunAsManager supports the type of secure object
+ that the security interceptor will present.
+
+ One concrete implementation of a RunAsManager
+ is provided with the Acegi Security System for Spring. The
+ RunAsManagerImpl class returns a replacement
+ RunAsUserToken if any
+ ConfigAttribute starts with
+ RUN_AS_. If any such
+ ConfigAttribute is found, the replacement
+ RunAsUserToken will contain the same principal,
+ credentials and granted authorities as the original
+ Authentication object, along with a new
+ GrantedAuthorityImpl for each
+ RUN_AS_ ConfigAttribute. Each
+ new GrantedAuthorityImpl will be prefixed with
+ ROLE_, followed by the RUN_AS
+ ConfigAttribute. For example, a
+ RUN_AS_SERVER will result in the replacement
+ RunAsUserToken containing a
+ ROLE_RUN_AS_SERVER granted authority.
+
+ The replacement RunAsUserToken is just like
+ any other Authentication object. It needs to be
+ authenticated by the AuthenticationManager,
+ probably via delegation to a suitable
+ AuthenticationProvider. The
+ RunAsImplAuthenticationProvider performs such
+ authentication. It simply accepts as valid any
+ RunAsUserToken presented.
+
+ To ensure malicious code does not create a
+ RunAsUserToken and present it for guaranteed
+ acceptance by the RunAsImplAuthenticationProvider,
+ the hash of a key is stored in all generated tokens. The
+ RunAsManagerImpl and
+ RunAsImplAuthenticationProvider is created in the
+ bean context with the same key:
+
+ <bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl">
+ <property name="key"><value>my_run_as_password</value></property>
+</bean><bean id="runAsAuthenticationProvider" class="net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider">
+ <property name="key"><value>my_run_as_password</value></property>
+</bean>
+
+ By using the same key, each RunAsUserToken
+ can be validated it was created by an approved
+ RunAsManagerImpl. The
+ RunAsUserToken is immutable after creation for
+ security reasons.
+
+
+
+
+ User Interfacing with the ContextHolder
+
+
+ Purpose
+
+ Everything presented so far assumes one thing: the
+ ContextHolder is populated with a valid
+ SecureContext, which in turn contains a valid
+ Authentication object. Developers are free to do
+ this in whichever way they like, such as directly calling the relevant
+ objects at runtime. However, several classes have been provided to
+ make this process transparent in many situations.
+
+ The net.sf.acegisecurity.ui package is
+ designed to make interfacing web application user interfaces with the
+ ContextHolder as simple as possible. There are two
+ major steps in doing this:
+
+
+
+ Actually authenticate the user and place the resulting
+ Authentication object in a "well-known
+ location".
+
+
+
+ Extract the Authentication object from
+ the "well-known location" and place in into the
+ ContextHolder for the duration of the secure
+ object invocation.
+
+
+
+ There are several alternatives are available for the first step,
+ which will be briefly discussed in this chapter. The most popular
+ approach is HTTP Session Authentication, which uses the
+ HttpSession object and filters to authenticate the
+ user. Another approach is HTTP Basic Authentication, which allows
+ clients to use HTTP headers to present authentication information to
+ the Acegi Security System for Spring. Alternatively, you can also use
+ Yale Central Authentication Service (CAS) for enterprise-wide single
+ sign on. The final approach is via Container Adapters, which allow
+ supported web containers to perform the authentication themselves.
+ HTTP Session and Basic Authentication is discussed below, whilst CAS
+ and Container Adapters are discussed in separate sections of this
+ document.
+
+
+
+ HTTP Session Authentication
+
+ HTTP Session Authentication involves using the
+ AuthenticationProcessingFilter to process a login
+ form. The login form simply contains j_username and
+ j_password input fields, and posts to a URL that is
+ monitored by the filter (by default
+ j_acegi_security_check). The filter is defined in
+ web.xml behind a
+ FilterToBeanProxy as follows:
+
+ <filter>
+ <filter-name>Acegi Authentication Processing Filter</filter-name>
+ <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
+ <init-param>
+ <param-name>targetClass</param-name>
+ <param-value>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</param-value>
+ </init-param>
+</filter>
+
+<filter-mapping>
+ <filter-name>Acegi Authentication Processing Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>
+
+ For a discussion of FilterToBeanProxy, please
+ refer to the Filters section. The application context will need to
+ define the AuthenticationProcessingFilter:
+
+ <bean id="authenticationProcessingFilter" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="authenticationFailureUrl"><value>/acegilogin.jsp?login_error=1</value></property>
+ <property name="defaultTargetUrl"><value>/</value></property>
+ <property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
+</bean>
+
+ The configured AuthenticationManager
+ processes each authentication request. If authentication fails, the
+ browser will be redirected to the
+ authenticationFailureUrl. The
+ AuthenticationException will be placed into the
+ HttpSession attribute indicated by
+ AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY,
+ enabling a reason to be provided to the user on the error page.
+
+ If authentication is successful, the resulting
+ Authentication object will be placed into the
+ HttpSession attribute indicated by
+ HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY.
+ This becomes the "well-known location" from which the
+ Authentication object is later extracted.
+
+ Once the HttpSession has been updated, the
+ browser will need to be redirected to the target URL. The target URL
+ is usually indicated by the HttpSession attribute
+ specified by
+ AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY.
+ This attribute is automatically set by the
+ SecurityEnforcementFilter when an
+ AuthenticationException occurs, so that after login
+ is completed the user can return to what they were trying to access.
+ If for some reason the HttpSession does not
+ indicate the target URL, the browser will be redirected to the
+ defaultTargetUrl property.
+
+ Because this authentication approach is fully contained within a
+ single web application, HTTP Session Authentication is recommended to
+ be used instead of Container Adapters.
+
+
+
+ HTTP Basic Authentication
+
+ The Acegi Security System for Spring provides a
+ BasicProcessingFilter which is capable of
+ processing 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
+ BasicProcessingFilter conforms with this
+ RFC.
+
+ To implement HTTP Basic Authentication, it is necessary to add
+ the following filter to web.xml:
+
+ <filter>
+ <filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
+ <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
+ <init-param>
+ <param-name>targetClass</param-name>
+ <param-value>net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter</param-value>
+ </init-param>
+</filter>
+
+<filter-mapping>
+ <filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>
+
+ For a discussion of FilterToBeanProxy, please
+ refer to the Filters section. The application context will need to
+ define the BasicProcessingFilter and its required
+ collaborator:
+
+ <bean id="basicProcessingFilter" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter">
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="authenticationEntryPoint"><ref bean="authenticationEntryPoint"/></property>
+</bean>
+
+<bean id="authenticationEntryPoint" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
+ <property name="realmName"><value>Name Of Your Realm</value></property>
+</bean>
+
+ The configured AuthenticationManager
+ processes each authentication request. If authentication fails, the
+ configured AuthenticationEntryPoint will be used to
+ retry the authentication process. Usually you will use the
+ BasicProcessingFilterEntryPoint, which returns a
+ 401 response with a suitable header to retry HTTP Basic
+ authentication. If authentication is successful, the resulting
+ Authentication object will be placed into the
+ HttpSession attribute indicated by
+ HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY.
+ This becomes the "well-known location" from which the
+ Authentication object is later extracted.
+
+ 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 AuthenticationEntryPoint is called,
+ as discussed in the previous paragraph.
+
+ HTTP Basic Authentication is recommended to be used instead of
+ Container Adapters. It can be used in conjunction with HTTP Session
+ Authentication, as demonstrated in the Contacts sample application.
+ You can also use it instead of HTTP Session Authentication if you
+ wish.
+
+
+
+ Well-Known Location Integration
+
+ Once a web application has used either HTTP Session
+ Authentication, HTTP Basic Authentication, or a Container Adapter, an
+ Authentication object will exist in a well-known
+ location. The final step in automatically integrating the user
+ interface with the backend security interceptor is to extract this
+ Authentication object from the well-known location
+ and place it into a SecureContext in the
+ ContextHolder.
+
+ The AbstractIntegrationFilter and its
+ subclasses provide this well-known location integration. These classes
+ are standard filters, and at the start of each request they will
+ attempt to extract the Authentication object from a
+ well-known location. The Authentication object will
+ then be added to a SecureContext, the
+ SecureContext associated with the
+ ContextHolder for the duration of the request, and
+ the ContextHolder be cleared when the request is
+ finished. Four concrete subclasses of
+ AbstractIntegrationFilter are provided with the
+ Acegi Security System for Spring:
+
+
+
+ HttpSessionIntegrationFilter is used
+ with HTTP Session Authentication, HTTP Basic Authentication, or
+ any other approach that populates the
+ HttpSession accordingly. It extracts the
+ Authentication object from the
+ HttpSession attribute indicated by
+ HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY.
+
+
+
+ HttpRequestIntegrationFilter is used
+ with Catalina, Jetty and Resin Container Adapters. It extracts
+ the authentication information from
+ HttpServletRequest.getUserPrincipal().
+
+
+
+ JbossIntegrationFilter is used with the
+ JBoss Container Adapter. It extracts the authentication from
+ java:comp/env/security/subject.
+
+
+
+ AutoIntegrationFilter automatically
+ determines which filter to use. This makes a web application WAR
+ file more portable, as the web.xml is not
+ hard-coded to a specific
+ AbstractIntegrationFilter.
+
+
+
+ To define the AutoIntegrationFilter
+ (recommended), simply add the following to your web.xml:
+
+ <filter>
+ <filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
+ <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
+ <init-param>
+ <param-name>targetClass</param-name>
+ <param-value>net.sf.acegisecurity.ui.AutoIntegrationFilter</param-value>
+ </init-param>
+</filter>
+
+<filter-mapping>
+ <filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>
+
+ You will also need to add the following line to your application
+ context:
+
+ <bean id="autoIntegrationFilter" class="net.sf.acegisecurity.ui.AutoIntegrationFilter" />
+
+ Once in the ContextHolder, the standard Acegi
+ Security System for Spring classes can be used. Because
+ ContextHolder is a standard object which is
+ populated using a filter at the container level, JSPs and Servlets do
+ not need to use Spring's MVC packages. This enables those applications
+ that use other MVC frameworks to still leverage Spring's other
+ capabilities, with full authentication and authorization support. The
+ debug.jsp page provided with the sample application
+ demonstrates accessing the ContextHolder
+ independent of Spring's MVC packages.
+
+
+
+
+ Container Adapters
+
+
+ Overview
+
+ Early versions of the Acegi Security System for Spring
+ 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
+ Session Authentication and HTTP Basic Authentication approaches were
+ developed, and are today recommended for most applications.
+
+ Container Adapters enable the Acegi Security System for Spring
+ to integrate directly with the containers used to host end user
+ applications. This integration means that applications can continue to
+ leverage the authentication and authorization capabilities built into
+ containers (such as isUserInRole() and form-based
+ or basic authentication), whilst benefiting from the enhanced security
+ interception capabilities provided by the Acegi Security System for
+ Spring.
+
+ The integration between a container and the Acegi Security
+ System for Spring is achieved through an adapter. The adapter provides
+ a container-compatible user authentication provider, and needs to
+ return a container-compatible user object.
+
+ The adapter is instantiated by the container and is defined in a
+ container-specific configuration file. The adapter then loads a Spring
+ application context which defines the normal authentication manager
+ settings, such as the authentication providers that can be used to
+ authenticate the request. The application context is usually named
+ acegisecurity.xml and is placed in a
+ container-specific location.
+
+ The Acegi Security System for Spring currently supports Jetty,
+ Catalina (Tomcat), JBoss and Resin. Additional container adapters can
+ easily be written.
+
+
+
+ Adapter Authentication Provider
+
+ As is always the case, the container adapter generated
+ Authentication object still needs to be
+ authenticated by an AuthenticationManager when
+ requested to do so by the
+ AbstractSecurityInterceptor. The
+ AuthenticationManager needs to be certain the
+ adapter-provided Authentication object is valid and
+ was actually authenticated by a trusted adapter.
+
+ Adapters create Authentication objects which
+ are immutable and implement the AuthByAdapter
+ interface. These objects store the hash of a key that is defined by
+ the adapter. This allows the Authentication object
+ to be validated by the AuthByAdapterProvider. This
+ authentication provider is defined as follows:
+
+ <bean id="authByAdapterProvider" class="net.sf.acegisecurity.adapters.AuthByAdapterProvider">
+ <property name="key"><value>my_password</value></property>
+</bean>
+
+ The key must match the key that is defined in the
+ container-specific configuration file that starts the adapter. The
+ AuthByAdapterProvider automatically accepts as
+ valid any AuthByAdapter implementation that returns
+ the expected hash of the key.
+
+ To reiterate, this means the adapter will perform the initial
+ authentication using providers such as
+ DaoAuthenticationProvider, returning an
+ AuthByAdapter instance that contains a hash code of
+ the key. Later, when an application calls a security interceptor
+ managed resource, the AuthByAdapter instance in the
+ SecureContext in the
+ ContextHolder will be tested by the application's
+ AuthByAdapterProvider. There is no requirement for
+ additional authentication providers such as
+ DaoAuthenticationProvider within the
+ application-specific application context, as the only type of
+ Authentication instance that will be presented by
+ the application is from the container adapter.
+
+ Classloader issues are frequent with containers and the use of
+ container adapters illustrates this further. Each container requires a
+ very specific configuration. The installation instructions are
+ provided below. Once installed, please take the time to try the sample
+ application to ensure your container adapter is properly
+ configured.
+
+ When using container adapters with the
+ DaoAuthenticationProvider, ensure you set its
+ forcePrincipalAsString property to
+ true.
+
+
+
+ Catalina (Tomcat) Installation
+
+ The following was tested with Jakarta Tomcat 4.1.30 and 5.0.19.
+ We automatically test the following directions using our container
+ integration test system and these versions of Catalina
+ (Tomcat).
+
+ $CATALINA_HOME refers to the root of your
+ Catalina (Tomcat) installation.
+
+ Edit your $CATALINA_HOME/conf/server.xml file
+ so the <Engine> section contains only one
+ active <Realm> entry. An example realm
+ entry:
+
+ <Realm className="net.sf.acegisecurity.adapters.catalina.CatalinaAcegiUserRealm"
+ appContextLocation="conf/acegisecurity.xml"
+ key="my_password" />
+
+ Be sure to remove any other <Realm>
+ entry from your <Engine> section.
+
+ Copy acegisecurity.xml into
+ $CATALINA_HOME/conf.
+
+ Copy acegi-security-catalina-server.jar into
+ $CATALINA_HOME/server/lib.
+
+ Copy the following files into
+ $CATALINA_HOME/common/lib:
+
+
+
+ aopalliance.jar
+
+
+
+ spring.jar
+
+
+
+ acegi-security-catalina-common.jar
+
+
+
+ commons-codec.jar
+
+
+
+ burlap.jar
+
+
+
+ hessian.jar
+
+
+
+ None of the above JAR files (or
+ acegi-security.jar) should be in your application's
+ WEB-INF/lib. The realm name indicated in your
+ web.xml does not matter with Catalina.
+
+ We have received reports of problems using this Container
+ Adapter with Mac OS X. A work-around is to use a script such as
+ follows:
+
+ #!/bin/sh
+export CATALINA_HOME="/Library/Tomcat"
+export JAVA_HOME="/Library/Java/Home"
+cd /
+$CATALINA_HOME/bin/startup.sh
+
+
+
+ Jetty Installation
+
+ The following was tested with Jetty 4.2.18. We automatically
+ test the following directions using our container integration test
+ system and this version of Jetty.
+
+ $JETTY_HOME refers to the root of your Jetty
+ installation.
+
+ Edit your $JETTY_HOME/etc/jetty.xml file so
+ the <Configure class> section has a new
+ addRealm call:
+
+ <Call name="addRealm">
+ <Arg>
+ <New class="net.sf.acegisecurity.adapters.jetty.JettyAcegiUserRealm">
+ <Arg>Spring Powered Realm</Arg>
+ <Arg>my_password</Arg>
+ <Arg>etc/acegisecurity.xml</Arg>
+ </New>
+ </Arg>
+ </Call>
+
+ Copy acegisecurity.xml into
+ $JETTY_HOME/etc.
+
+ Copy the following files into
+ $JETTY_HOME/ext:
+
+ aopalliance.jar
+
+
+
+ commons-logging.jar
+
+
+
+ spring.jar
+
+
+
+ acegi-security-jetty-ext.jar
+
+
+
+ commons-codec.jar
+
+
+
+ burlap.jar
+
+
+
+ hessian.jar
+
+
+
+ None of the above JAR files (or
+ acegi-security.jar) should be in your application's
+ WEB-INF/lib. The realm name indicated in your
+ web.xml does matter with Jetty. The
+ web.xml must express the same
+ <realm-name> as your
+ jetty.xml (in the example above, "Spring Powered
+ Realm").
+
+
+
+ JBoss Installation
+
+ The following was tested with JBoss 3.2.3. We automatically test
+ the following directions using our container integration test system
+ and this version of JBoss.
+
+ $JBOSS_HOME refers to the root of your JBoss
+ installation.
+
+ Edit your
+ $JBOSS_HOME/server/your_config/conf/login-config.xml
+ file so that it contains a new entry under the
+ <Policy> section:
+
+ <application-policy name = "SpringPoweredRealm">
+ <authentication>
+ <login-module code = "net.sf.acegisecurity.adapters.jboss.JbossSpringLoginModule"
+ flag = "required">
+ <module-option name = "appContextLocation">acegisecurity.xml</module-option>
+ <module-option name = "key">my_password</module-option>
+ </login-module>
+ </authentication>
+ </application-policy>
+
+ Copy acegisecurity.xml into
+ $JBOSS_HOME/server/your_config/conf.
+
+ Copy the following files into
+ $JBOSS_HOME/server/your_config/lib:
+
+ aopalliance.jar
+
+
+
+ spring.jar
+
+
+
+ acegi-security-jboss-lib.jar
+
+
+
+ commons-codec.jar
+
+
+
+ burlap.jar
+
+
+
+ hessian.jar
+
+
+
+ None of the above JAR files (or
+ acegi-security.jar) should be in your application's
+ WEB-INF/lib. The realm name indicated in your
+ web.xml does not matter with JBoss. However, your
+ web application's WEB-INF/jboss-web.xml must
+ express the same <security-domain> as your
+ login-config.xml. For example, to match the above
+ example, your jboss-web.xml would look like
+ this:
+
+ <jboss-web>
+ <security-domain>java:/jaas/SpringPoweredRealm</security-domain>
+</jboss-web>
+
+
+
+ Resin Installation
+
+ The following was tested with Resin 3.0.6.
+
+ $RESIN_HOME refers to the root of your Resin
+ installation.
+
+ Resin provides several ways to support the container adapter. In
+ the instructions below we have elected to maximise consistency with
+ other container adapter configurations. This will allow Resin users to
+ simply deploy the sample application and confirm correct
+ configuration. Developers comfortable with Resin are naturally able to
+ use its capabilities to package the JARs with the web application
+ itself, and/or support single sign-on.
+
+ Copy the following files into
+ $RESIN_HOME/lib:
+
+ aopalliance.jar
+
+
+
+ commons-logging.jar
+
+
+
+ spring.jar
+
+
+
+ acegi-security-resin-lib.jar
+
+
+
+ commons-codec.jar
+
+
+
+ burlap.jar
+
+
+
+ hessian.jar
+
+
+
+ Unlike the container-wide acegisecurity.xml
+ files used by other container adapters, each Resin web application
+ will contain its own
+ WEB-INF/resin-acegisecurity.xml file. Each web
+ application will also contain a resin-web.xml file
+ which Resin uses to start the container adapter:
+
+ <web-app>
+ <authenticator>
+ <type>net.sf.acegisecurity.adapters.resin.ResinAcegiAuthenticator</type>
+ <init>
+ <app-context-location>WEB-INF/resin-acegisecurity.xml</app-context-location>
+ <key>my_password</key>
+ </init>
+ </authenticator>
+</web-app>
+
+ With the basic configuration provided above, none of the JAR
+ files listed (or acegi-security.jar) should be in
+ your application's WEB-INF/lib. The realm name
+ indicated in your web.xml does not matter with
+ Resin, as the relevant authentication class is indicated by the
+ <authenticator> setting.
+
+
+
+
+ Yale Central Authentication Service (CAS) Single Sign On
+
+
+ Overview
+
+ Yale University produces an enterprise-wide single sign on
+ system known as CAS. Unlike other initiatives, Yale's Central
+ Authentication Service is open source, widely used, simple to
+ understand, platform independent, and supports proxy capabilities. The
+ Acegi Security System for Spring 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.
+
+ You can learn more about CAS at
+ http://www.yale.edu/tp/auth/. You will need to
+ visit this URL to download the CAS Server files. Whilst the Acegi
+ Security System for Spring includes two CAS libraries in the
+ "-with-dependencies" ZIP file, you will still need the CAS Java Server
+ Pages and web.xml to customise and deploy your CAS
+ server.
+
+
+
+ How CAS Works
+
+ 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 the Acegi Security System for Spring. The
+ following refers to CAS 2.0, being the version of CAS that Acegi
+ Security System for Spring supports.
+
+ 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. You will also need to specify in the web.xml a
+ PasswordHandler. The
+ PasswordHandler has a simple method that returns a
+ boolean as to whether a given username and password is valid. Your
+ PasswordHandler implementation will need to link
+ into some type of backend authentication repository, such as an LDAP
+ server or database.
+
+ If you are already running an existing CAS server instance, you
+ will have already established a PasswordHandler. If
+ you do not already have a PasswordHandler, you
+ might prefer to use the Acegi Security System for Spring
+ CasPasswordHandler class. This class delegates
+ through to the standard Acegi Security
+ AuthenticationManager, enabling you to use a
+ security configuration you might already have in place. You do not
+ need to use the CasPasswordHandler class on your
+ CAS server if you do not wish. The Acegi Security System for Spring
+ will function as a CAS client successfully irrespective of the
+ PasswordHandler you've chosen for your CAS
+ server.
+
+ 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.
+
+ Services can be developed in a large variety of languages, due
+ to CAS 2.0's very light XML-based protocol. The Yale 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 the
+ Acegi Security System for Spring. This is handled transparently for
+ you.
+
+ The basic interaction between a web browser, CAS server and an
+ Acegi Security for System Spring secured service is as follows:
+
+
+
+ The web user is browsing the service's public pages. CAS or
+ Acegi Security is not involved.
+
+
+
+ The user eventually requests a page that is either secure or
+ one of the beans it uses is secure. Acegi Security's
+ SecurityEnforcementFilter will detect the
+ AuthenticationException.
+
+
+
+ Because the user's Authentication object
+ (or lack thereof) caused an
+ AuthenticationException, the
+ SecurityEnforcementFilter will call the
+ configured AuthenticationEntryPoint. If using
+ CAS, this will be the
+ CasProcessingFilterEntryPoint class.
+
+
+
+ The CasProcessingFilterEntry point will
+ redirect the user's browser to the CAS server. It will also
+ indicate a service parameter, which is the
+ callback URL for the Acegi Security service. For example, the URL
+ to which the browser is redirected might be
+ https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_acegi_cas_security_check.
+
+
+
+ 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
+ PasswordHandler discussed above to decide
+ whether the username and password is valid.
+
+
+
+ Upon successful login, CAS will redirect the user's browser
+ back to the original service. It will also include a
+ ticket parameter, which is an opaque string
+ representing the "service ticket". Continuing our earlier example,
+ the URL the browser is redirected to might be
+ https://server3.company.com/webapp/j_acegi_cas_security_check?ticket=ST-0-ER94xMJmn6pha35CQRoZ.
+
+
+
+ Back in the service web application, the
+ CasProcessingFilter is always listening for
+ requests to /j_acegi_cas_security_check (this
+ is configurable, but we'll use the defaults in this introduction).
+ The processing filter will construct a
+ UsernamePasswordAuthenticationToken
+ representing the service ticket. The principal will be equal to
+ CasProcessingFilter.CAS_STATEFUL_IDENTIFIER,
+ whilst the credentials will be the service ticket opaque value.
+ This authentication request will then be handed to the configured
+ AuthenticationManager.
+
+
+
+ The AuthenticationManager implementation
+ will be the ProviderManager, which is in turn
+ configured with the CasAuthenticationProvider.
+ The CasAuthenticationProvider only responds to
+ UsernamePasswordAuthenticationTokens containing
+ the CAS-specific principal (such as
+ CasProcessingFilter.CAS_STATEFUL_IDENTIFIER)
+ and CasAuthenticationTokens (discussed
+ later).
+
+
+
+ CasAuthenticationProvider will validate
+ the service ticket using a TicketValidator
+ implementation. Acegi Security includes one implementation, the
+ CasProxyTicketValidator. This implementation a
+ ticket validation class included in the CAS client library. The
+ CasProxyTicketValidator makes a HTTPS request
+ to the CAS server in order to validate the service ticket. The
+ CasProxyTicketValidator may also include a
+ proxy callback URL, which is included in this example:
+ https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_acegi_cas_security_check&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/casProxy/receptor.
+
+
+
+ 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.
+
+
+
+ [OPTIONAL] If the request to the CAS validation service
+ included the proxy callback URL (in the pgtUrl
+ parameter), CAS will include a pgtIou string in
+ the XML response. This pgtIou represents a
+ proxy-granting ticket IOU. The CAS server will then create its own
+ HTTPS connection back to the pgtUrl. 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,
+ https://server3.company.com/webapp/casProxy/receptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH.
+ We suggest you use CAS' ProxyTicketReceptor
+ servlet to receive these proxy-granting tickets, if they are
+ required.
+
+
+
+ The CasProxyTicketValidator will parse
+ the XML received from the CAS server. It will return to the
+ CasAuthenticationProvider a
+ TicketResponse, which includes the username
+ (mandatory), proxy list (if any were involved), and proxy-granting
+ ticket IOU (if the proxy callback was requested).
+
+
+
+ Next CasAuthenticationProvider will call
+ a configured CasProxyDecider. The
+ CasProxyDecider indicates whether the proxy
+ list in the TicketResponse is acceptable to the
+ service. Several implementations are provided with the Acegi
+ Security System: RejectProxyTickets,
+ AcceptAnyCasProxy and
+ NamedCasProxyDecider. These names are largely
+ self-explanatory, except NamedCasProxyDecider
+ which allows a List of trusted proxies to be
+ provided.
+
+
+
+ CasAuthenticationProvider will next
+ request a CasAuthoritiesPopulator to advise the
+ GrantedAuthority objects that apply to the user
+ contained in the TicketResponse. Acegi Security
+ includes a DaoCasAuthoritiesPopulator which
+ simply uses the AuthenticationDao
+ infrastructure to find the UserDetails and
+ their associated GrantedAuthoritys. Note that
+ the password and enabled/disabled status of
+ UserDetails returned by the
+ AuthenticationDao are ignored, as the CAS
+ server is responsible for authentication decisions.
+ DaoCasAuthoritiesPopulator is only concerned
+ with retrieving the GrantedAuthoritys.
+
+
+
+ If there were no problems,
+ CasAuthenticationProvider constructs a
+ CasAuthenticationToken including the details
+ contained in the TicketResponse and the
+ GrantedAuthoritys. The
+ CasAuthenticationToken contains the hash of a
+ key, so that the CasAuthenticationProvider
+ knows it created it.
+
+
+
+ Control then returns to
+ CasProcessingFilter, which places the created
+ CasAuthenticationToken into the
+ HttpSession attribute named
+ HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY.
+
+
+
+ The user's browser is redirected to the original page that
+ caused the AuthenticationException.
+
+
+
+ As the Authentication object is now in
+ the well-known location, it is handled like any other
+ authentication approach. Usually the
+ AutoIntegrationFilter will be used to associate
+ the Authentication object with the
+ ContextHolder for the duration of each
+ request.
+
+
+
+ It's good that you're still here! It might sound involved, but
+ you can relax as the Acegi Security System for Spring classes hide
+ much of the complexity. Let's now look at how this is
+ configured.
+
+
+
+ CAS Server Installation (Optional)
+
+ As mentioned above, the Acegi Security System for Spring
+ includes a PasswordHandler that bridges your
+ existing AuthenticationManager into CAS. You do not
+ need to use this PasswordHandler to use Acegi
+ Security on the client side (any CAS
+ PasswordHandler will do).
+
+ To install, you will need to download and extract the CAS server
+ archive. We used version 2.0.12. There will be a
+ /web directory in the root of the deployment. Copy
+ an applicationContext.xml containing your
+ AuthenticationManager as well as the
+ CasPasswordHandler into the
+ /web/WEB-INF directory. A sample
+ applicationContext.xml is included below:
+
+ <bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
+ <property name="userMap">
+ <value>
+ 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
+ </value>
+ </property>
+</bean>
+
+<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
+ <property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
+</bean>
+
+<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
+ <property name="providers">
+ <list>
+ <ref bean="daoAuthenticationProvider"/>
+ </list>
+ </property>
+</bean>
+
+<bean id="casPasswordHandler" class="net.sf.acegisecurity.adapters.cas.CasPasswordHandler">
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+</bean>
+
+ 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).
+
+ Next you will need to edit the existing
+ /web/WEB-INF/web.xml file. Add (or edit in the case
+ of the authHandler property) the following
+ lines:
+
+ <context-param>
+ <param-name>edu.yale.its.tp.cas.authHandler</param-name>
+ <param-value>net.sf.acegisecurity.adapters.cas.CasPasswordHandlerProxy</param-value>
+</context-param>
+
+<context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>/WEB-INF/applicationContext.xml</param-value>
+</context-param>
+
+<listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+</listener>
+
+ Copy the spring.jar and
+ acegi-security.jar files into
+ /web/WEB-INF/lib. Now use the ant
+ dist task in the build.xml in the root of
+ the directory structure. This will create
+ /lib/cas.war, which is ready for deployment to your
+ servlet container.
+
+ 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
+ samples/contacts/etc/ssl directory.
+
+
+
+ CAS Acegi Security System Client Installation
+
+ The web application side of CAS is made easy due to the Acegi
+ Security System for Spring. It is assumed you already know the basics
+ of using the Acegi Security System for Spring, so these are not
+ covered again below. Only the CAS-specific beans are mentioned.
+
+ You will need to add a ServiceProperties bean
+ to your application context. This represents your service:
+
+ <bean id="serviceProperties" class="net.sf.acegisecurity.ui.cas.ServiceProperties">
+ <property name="service"><value>https://localhost:8443/contacts-cas/j_acegi_cas_security_check</value></property>
+ <property name="sendRenew"><value>false</value></property>
+</bean>
+
+ The service must equal a URL that will be
+ monitored by the CasProcessingFilter. The
+ sendRenew 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.
+
+ The following beans should be configured to commence the CAS
+ authentication process:
+
+ <bean id="casProcessingFilter" class="net.sf.acegisecurity.ui.cas.CasProcessingFilter">
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="authenticationFailureUrl"><value>/casfailed.jsp</value></property>
+ <property name="defaultTargetUrl"><value>/</value></property>
+ <property name="filterProcessesUrl"><value>/j_acegi_cas_security_check</value></property>
+</bean>
+
+<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
+ <property name="filterSecurityInterceptor"><ref bean="filterInvocationInterceptor"/></property>
+ <property name="authenticationEntryPoint"><ref bean="casProcessingFilterEntryPoint"/></property>
+</bean>
+
+<bean id="casProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.cas.CasProcessingFilterEntryPoint">
+ <property name="loginUrl"><value>https://localhost:8443/cas/login</value></property>
+ <property name="serviceProperties"><ref bean="serviceProperties"/></property>
+</bean>
+
+ You will also need to add the
+ CasProcessingFilter to web.xml:
+
+ <filter>
+ <filter-name>Acegi CAS Processing Filter</filter-name>
+ <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
+ <init-param>
+ <param-name>targetClass</param-name>
+ <param-value>net.sf.acegisecurity.ui.cas.CasProcessingFilter</param-value>
+ </init-param>
+</filter>
+
+<filter-mapping>
+ <filter-name>Acegi CAS Processing Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>
+
+ The CasProcessingFilter has very similar
+ properties to the AuthenticationProcessingFilter
+ (used for form-based logins). Each property is
+ self-explanatory.
+
+ For CAS to operate, the
+ SecurityEnforcementFilter must have its
+ authenticationEntryPoint property set to the
+ CasProcessingFilterEntryPoint bean.
+
+ The CasProcessingFilterEntryPoint must refer
+ to the ServiceProperties bean (discussed above),
+ which provides the URL to the enterprise's CAS login server. This is
+ where the user's browser will be redirected.
+
+ Next you need to add an AuthenticationManager
+ that uses CasAuthenticationProvider and its
+ collaborators:
+
+ <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
+ <property name="providers">
+ <list>
+ <ref bean="casAuthenticationProvider"/>
+ </list>
+ </property>
+</bean>
+
+<bean id="casAuthenticationProvider" class="net.sf.acegisecurity.providers.cas.CasAuthenticationProvider">
+ <property name="casAuthoritiesPopulator"><ref bean="casAuthoritiesPopulator"/></property>
+ <property name="casProxyDecider"><ref bean="casProxyDecider"/></property>
+ <property name="ticketValidator"><ref bean="casProxyTicketValidator"/></property>
+ <property name="statelessTicketCache"><ref bean="statelessTicketCache"/></property>
+ <property name="key"><value>my_password_for_this_auth_provider_only</value></property>
+</bean>
+
+<bean id="casProxyTicketValidator" class="net.sf.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator">
+ <property name="casValidate"><value>https://localhost:8443/cas/proxyValidate</value></property>
+ <property name="proxyCallbackUrl"><value>https://localhost:8443/contacts-cas/casProxy/receptor</value></property>
+ <property name="serviceProperties"><ref bean="serviceProperties"/></property>
+ <!-- <property name="trustStore"><value>/some/path/to/your/lib/security/cacerts</value></property> -->
+</bean>
+
+<bean id="statelessTicketCache" class="net.sf.acegisecurity.providers.cas.cache.EhCacheBasedTicketCache">
+ <property name="minutesToIdle"><value>20</value></property>
+</bean>
+
+<bean id="casAuthoritiesPopulator" class="net.sf.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator">
+ <property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
+</bean>
+
+<bean id="casProxyDecider" class="net.sf.acegisecurity.providers.cas.proxy.RejectProxyTickets"/>
+
+ The beans are all reasonable self-explanatory if you refer back
+ to the "How CAS Works" section. Careful readers might notice one
+ surprise: the statelessTicketCache property of the
+ CasAuthenticationProvider. This is discussed in
+ detail in the "Advanced CAS Usage" section.
+
+ Note the CasProxyTicketValidator has a
+ remarked out trustStore property. This property
+ might be helpful if you experience HTTPS certificate issues. Also note
+ the proxyCallbackUrl 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'
+ ProxyTicketReceptor by adding the following to your
+ web application's web.xml:
+
+ <servlet>
+ <servlet-name>casproxy</servlet-name>
+ <servlet-class>edu.yale.its.tp.cas.proxy.ProxyTicketReceptor</servlet-class>
+</servlet>
+
+<servlet-mapping>
+ <servlet-name>casproxy</servlet-name>
+ <url-pattern>/casProxy/*</url-pattern>
+</servlet-mapping>
+
+ 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 the Acegi Security
+ System for Spring need to be concerned about the fact CAS handled
+ authentication.
+
+ There is also a contacts-cas.war file in the
+ sample applications directory. This sample application uses the above
+ settings and can be deployed to see CAS in operation.
+
+
+
+ Advanced CAS Usage
+
+ The CasAuthenticationProvider distinguishes
+ between stateful and stateless clients. A stateful client is
+ considered any that originates via the
+ CasProcessingFilter. A stateless client is any that
+ presents an authentication request via the
+ UsernamePasswordAuthenticationToken with a
+ principal equal to
+ CasProcessingFilter.CAS_STATELESS_IDENTIFIER.
+
+ Stateless clients are likely to be via remoting protocols such
+ as Hessian and Burlap. The BasicProcessingFilter 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.
+
+ Because remoting protocols have no way of presenting themselves
+ within the context of a HttpSession, it isn't
+ possible to rely on the HttpSession's
+ HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY
+ attribute to locate the CasAuthenticationToken.
+ Furthermore, because the CAS server invalidates a service ticket after
+ it has been validated by the TicketValidator,
+ 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.
+
+ 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.
+
+ As a middle-ground, the
+ CasAuthenticationProvider uses a
+ StatelessTicketCache. This is used solely for
+ requests with a principal equal to
+ CasProcessingFilter.CAS_STATELESS_IDENTIFIER. What
+ happens is the CasAuthenticationProvider will store
+ the resulting CasAuthenticationToken in the
+ StatelessTicketCache, keyed on the service ticket.
+ Accordingly, remoting protocol clients can present the same service
+ ticket and the CasAuthenticationProvider will not
+ need to contact the CAS server for validation (aside from the first
+ request).
+
+ The other aspect of advanced CAS usage involves creating proxy
+ tickets from the proxy-granting ticket. As indicated above, we
+ recommend you use CAS' ProxyTicketReceptor to
+ receive these tickets. The ProxyTicketReceptor
+ 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
+ CasAuthenticationToken.getProxyGrantingTicketIou().
+
+ It is hoped you find CAS integration easy and useful with the
+ Acegi Security System for Spring classes. Welcome to enterprise-wide
+ single sign on!
+
+
+
+
+ Channel Security
+
+
+ Overview
+
+ In addition to coordinating the authentication and authorization
+ requirements of your application, the Acegi Security System for Spring
+ is also able to ensure unauthenticated web requests have certain
+ properties. These properties may include being of a particular
+ transport type, having a particular HttpSession
+ 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.
+
+ An important issue in considering transport security is that of
+ session hijacking. Your web container manages a
+ HttpSession by reference to a
+ jsessionid that is sent to user agents either via a
+ cookie or URL rewriting. If the jsessionid 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.
+
+ 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 jsessionid is never sent
+ across an insecure channel. You will need to ensure your
+ web.xml-defined
+ <welcome-file> points to a HTTPS location,
+ and the application never directs the user to a HTTP location. The
+ Acegi Security System for Spring provides a solution to assist with
+ the latter.
+
+
+
+ Configuration
+
+ To utilise Acegi Security's channel security services, add the
+ following lines to web.xml:
+
+ <filter>
+ <filter-name>Acegi Channel Processing Filter</filter-name>
+ <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
+ <init-param>
+ <param-name>targetClass</param-name>
+ <param-value>net.sf.acegisecurity.securechannel.ChannelProcessingFilter</param-value>
+ </init-param>
+</filter>
+
+<filter-mapping>
+ <filter-name>Acegi Channel Processing Filter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>
+
+ As usual when running FilterToBeanProxy, you
+ will also need to configure the filter in your application
+ context:
+
+ <bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter">
+ <property name="channelDecisionManager"><ref bean="channelDecisionManager"/></property>
+ <property name="filterInvocationDefinitionSource">
+ <value>
+ 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
+ </value>
+ </property>
+</bean>
+
+<bean id="channelDecisionManager" class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl">
+ <property name="channelProcessors">
+ <list>
+ <ref bean="secureChannelProcessor"/>
+ <ref bean="insecureChannelProcessor"/>
+ </list>
+ </property>
+</bean>
+
+<bean id="secureChannelProcessor" class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/>
+<bean id="insecureChannelProcessor" class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/>
+
+ Like FilterSecurityInterceptor, Apache Ant
+ style paths are also supported by the
+ ChannelProcessingFilter.
+
+ The ChannelProcessingFilter operates by
+ filtering all web requests and determining the configuration
+ attributes that apply. It then delegates to the
+ ChannelDecisionManager. The default implementation,
+ ChannelDecisionManagerImpl, should suffice in most
+ cases. It simply delegates through the list of configured
+ ChannelProcessor instances. A
+ ChannelProcessor 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.
+
+ Included with the Acegi Security System for Spring are two
+ concrete ChannelProcessor implementations:
+ SecureChannelProcessor ensures requests with a
+ configuration attribute of REQUIRES_SECURE_CHANNEL
+ are received over HTTPS, whilst
+ InsecureChannelProcessor ensures requests with a
+ configuration attribute of
+ REQUIRES_INSECURE_CHANNEL are received over HTTP.
+ Both implementations delegate to a
+ ChannelEntryPoint if the required transport
+ protocol is not used. The two ChannelEntryPoint
+ implementations included with Acegi Security simply redirect the
+ request to HTTP and HTTPS as appropriate. Appropriate defaults are
+ assigned to the ChannelProcessor implementations
+ for the configuration attribute keywords they respond to and the
+ ChannelEntryPoint they delegate to, although you
+ have the ability to override these using the application
+ context.
+
+ Note that the redirections are absolute (eg
+ http://www.company.com:8080/app/page), not relative (eg /app/page).
+ 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
+ PortResolverImpl that is wired up by default to
+ many Acegi Security beans. Please refer to the JavaDocs for
+ PortResolverImpl for further details.
+
+
+
+ Usage
+
+ 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
+ web.xml <welcome-file> or
+ a well-known home page URL), but once this is done the filter will
+ perform redirects as defined by your application context.
+
+ You can also add your own ChannelProcessor
+ implementations to the ChannelDecisionManagerImpl.
+ For example, you might set a HttpSession attribute
+ when a human user is detected via a "enter the contents of this
+ graphic" procedure. Your ChannelProcessor would
+ respond to say REQUIRES_HUMAN_USER configuration
+ attributes and redirect to an appropriate entry point to start the
+ human user validation process if the HttpSession
+ attribute is not currently set.
+
+ To decide whether a security check belongs in a
+ ChannelProcessor or an
+ AccessDecisionVoter, 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 ChannelProcessor
+ will generally cause a HTTP/HTTPS redirection so its requirements can
+ be met, whilst problems detected by an
+ AccessDecisionVoter will ultimately result in an
+ AccessDeniedException (depending on the governing
+ AccessDecisionManager).
+
+
+
+
+ Instance-Based Access Control List (ACL) Security
+
+
+ Overview
+
+ THIS FEATURE WAS ADDED IN VERSION 0.6. WE WELCOME YOUR COMMENTS
+ AND IMPROVEMENTS.
+
+ 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
+ (Authentication), where
+ (MethodInvocation) and what
+ (SomeDomainObject). In other words, authorization
+ decisions also need to consider the actual domain object instance
+ subject of a method invocation.
+
+ 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 System for Spring as
+ the foundation, you have several approaches that can be
+ used:
+
+ Write your business methods to enforce the security. You
+ could consult a collection within the
+ Customer domain object instance to determine
+ which users have access. By using the
+ ContextHolder.getContext() and casting it to
+ SecureContext, you'll be able to access the
+ Authentication object.
+
+
+
+ Write an AccessDecisionVoter to enforce
+ the security from the GrantedAuthority[]s
+ stored in the Authentication object. This
+ would mean your AuthenticationManager would
+ need to populate the Authentication with
+ custom GrantedAuthority[]s representing each
+ of the Customer domain object instances the
+ principal has access to.
+
+
+
+ Write an AccessDecisionVoter to enforce
+ the security and open the target Customer
+ domain object directly. This would mean your voter needs access
+ to a DAO that allows it to retrieve the
+ Customer object. It would then access the
+ Customer object's collection of approved
+ users and make the appropriate decision.
+
+
+
+ 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
+ Customer authorization logic elsewhere. Obtaining
+ the GrantedAuthority[]s from the
+ Authentication object is also fine, but will not
+ scale to large numbers of Customers. If a user
+ might be able to access 5,000 Customers (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 Authentication object would be undesirable. The
+ final method, opening the Customer 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
+ AccessDecisionVoter and the eventual business
+ method itself will perform a call to the DAO responsible for
+ retrieving the Customer 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.
+
+ Fortunately, there is another alternative, which we'll talk
+ about below.
+
+
+
+ The net.sf.acegisecurity.acl Package
+
+ The net.sf.acegisecurity.acl package is very
+ simple, comprising only a handful of interfaces and a single class. It
+ provides the basic foundation for access control list (ACL) lookups.
+ The central interface is AclManager, which is
+ defined by two methods:
+
+ public AclEntry[] getAcls(java.lang.Object domainInstance);
+public AclEntry[] getAcls(java.lang.Object domainInstance, Authentication authentication);
+
+ AclManager is intended to be used as a
+ collaborator against your business objects, or, more desirably,
+ AccessDecisionVoters. This means you use Spring's
+ normal ApplicationContext features to wire up your
+ AccessDecisionVoter (or business method) with an
+ AclManager. Consideration was given to placing the
+ ACL information in the ContextHolder, 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.
+
+ The first method of the AclManager 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 Authentication object.
+
+ The AclEntry interface returned by
+ AclManager is merely a marker interface. You will
+ need to provide an implementation that reflects that ACL permissions
+ for your application.
+
+ Rounding out the net.sf.acegisecurity.acl
+ package is an AclProviderManager class, with a
+ corresponding AclProvider interface.
+ AclProviderManager is a concrete implementation of
+ AclManager, which iterates through registered
+ AclProviders. The first
+ AclProvider that indicates it can authoritatively
+ provide ACL information for the presented domain object instance will
+ be used. This is very similar to the
+ AuthenticationProvider interface used for
+ authentication.
+
+ With this background, let's now look at a usable ACL
+ implementation.
+
+
+
+ Integer Masked ACLs
+
+ Acegi Security System for Spring includes a production-quality
+ ACL provider implementation. 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
+ chmod command will know all about this type of
+ permission masking (eg chmod 777). You'll find the
+ classes and interfaces for the integer masking ACL package under
+ net.sf.acegisecurity.acl.basic.
+
+ Extending the AclEntry interface is a
+ BasicAclEntry interface, with the main methods
+ shown below:
+
+ public AclObjectIdentity getAclObjectIdentity();
+public AclObjectIdentity getAclObjectParentIdentity();
+public int getMask();
+public java.lang.Object getRecipient();
+
+ As shown, each BasicAclEntry has four main
+ properties. The mask is the integer that represents
+ the permissions granted to the recipient. The
+ aclObjectIdentity is able to identify the domain
+ object instance for which the ACL applies, and the
+ aclObjectParentIdentity optionally specifies the
+ parent of the domain object instance. Multiple
+ BasicAclEntrys 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).
+
+ BasicAclEntry implementations typically
+ provide convenience methods, such as
+ isReadAllowed(), to avoid application classes
+ needing to perform bit masking themselves. The
+ SimpleAclEntry and
+ AbstractBasicAclEntry demonstrate and provide much
+ of this bit masking logic.
+
+ The AclObjectIdentity itself is merely a
+ marker interface, so you need to provide implementations for your
+ domain objects. However, the package does include a
+ NamedEntityObjectIdentity implementation which will
+ suit many needs. The NamedEntityObjectIdentity
+ identifies a given domain object instance by the classname of the
+ instance and the identity of the instance. A
+ NamedEntityObjectIdentity can be constructed
+ manually (by calling the constructor and providing the classname and
+ identity Strings), or by passing in any domain
+ object that contains a getId() method.
+
+ The actual AclProvider implementation is
+ named BasicAclProvider. It has adopted a similar
+ design to that used by the authentication-related
+ DaoAuthenticationProvder. Specifically, you define
+ a BasicAclDao against the provider, so different
+ ACL repository types can be accessed in a pluggable manner. The
+ BasicAclProvider also supports pluggable cache
+ providers (with Acegi Security System for Spring including an
+ implementation that fronts EH-CACHE).
+
+ The BasicAclDao interface is very simple to
+ implement:
+
+ public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity);
+
+ A BasicAclDao implementation needs to
+ understand the presented AclObjectIdentity and how
+ it maps to a storage repository, find the relevant records, and create
+ appropriate BasicAclEntry objects and return
+ them.
+
+ Acegi Security includes a single BasicAclDao
+ implementation called JdbcDaoImpl. As implied by
+ the name, it accesses ACL information from a JDBC database. The
+ default database schema and some sample data will aid in understanding
+ its function:
+
+ 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, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');
+INSERT INTO acl_object_identity VALUES (2, 'corp.DomainObject:2', 1, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');
+INSERT INTO acl_object_identity VALUES (3, 'corp.DomainObject:3', 1, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');
+INSERT INTO acl_object_identity VALUES (4, 'corp.DomainObject:4', 1, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');
+INSERT INTO acl_object_identity VALUES (5, 'corp.DomainObject:5', 3, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');
+INSERT INTO acl_object_identity VALUES (6, 'corp.DomainObject:6', 3, 'net.sf.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);
+
+ 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 JdbcDaoImpl will only respond to requests
+ for NamedEntityObjectIdentitys. It converts such
+ identities into a single String, comprising
+ the NamedEntityObjectIdentity.getClassname() +
+ ":" +
+ NamedEntityObjectIdentity.getId(). This yields the
+ type of object_identity values shown above. As
+ indicated by the sample data, each database row corresponds to a
+ single BasicAclEntry. As stated earlier and
+ demonstrated by corp.DomainObject:2 in the above
+ sample data, each domain object instance will often have multiple
+ BasicAclEntry[]s.
+
+ As JdbcDaoImpl is required to return concrete
+ BasicAclEntry classes, it needs to know which
+ BasicAclEntry implementation it is to create and
+ populate. This is the role of the acl_class column.
+ JdbcDaoImpl will create the indicated class and set
+ its mask, recipient,
+ aclObjectIdentity and
+ aclObjectParentIdentity properties.
+
+ As you can probably tell from the sample data, the
+ parent_object_identity value can either be null or
+ in the same format as the object_identity. If
+ non-null, JdbcDaoImpl will create a
+ NamedEntityObjectIdentity to place inside the
+ returned BasicAclEntry class.
+
+ Returning to the BasicAclProvider, before it
+ can poll the BasicAclDao implementation it needs to
+ convert the domain object instance it was passed into an
+ AclObjectIdentity.
+ BasicAclProvider has a protected
+ AclObjectIdentity obtainIdentity(Object domainInstance)
+ 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
+ AclObjectIdentityAware interface, which is merely a
+ getter for an AclObjectIdentity. 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 AclObjectIdentity by
+ passing the domain object instance to the constructor of a class
+ defined by the
+ BasicAclProvider.getDefaultAclObjectIdentity()
+ method. By default the defined class is
+ NamedEntityObjectIdentity, which was described in
+ more detail above. Therefore, you will need to either (i) provide a
+ getId() method on your domain objects, (ii)
+ implement AclObjectIdentityAware on your domain
+ objects, (iii) provide an alternative
+ AclObjectIdentity implementation that will accept
+ your domain object in its constructor, or (iv) override the
+ obtainIdentity(Object) method.
+
+ Once the AclObjectIdentity of the domain
+ object instance is determined, the BasicAclProvider
+ will poll the DAO to obtain its BasicAclEntry[]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
+ recipient 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:
+
+ --- 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)
+
+ So the above explains how a domain object instance has its
+ AclObjectIdentity discovered, and the
+ BasicAclDao will be polled successively until an
+ array of inherited permissions is constructed for the domain object
+ instance. The final step is to determine the
+ BasicAclEntry[]s that are actually applicable to a
+ given Authentication object.
+
+ As you would recall, the AclManager (and all
+ delegates, up to and including BasicAclProvider)
+ provides a method which returns only those
+ BasicAclEntry[]s applying to a passed
+ Authentication object.
+ BasicAclProvider delivers this functionality by
+ delegating the filtering operation to an
+ EffectiveAclsResolver implementation. The default
+ implementation,
+ GrantedAuthorityEffectiveAclsResolver, will iterate
+ through the BasicAclEntry[]s and include only those
+ where the recipient is equal to either the
+ Authentication's principal or
+ any of the Authentication's
+ GrantedAuthority[]s. Please refer to the JavaDocs
+ for more information.
+
+
+
+ Conclusion
+
+ Acegi Security's instance-specific ACL packages shield you from
+ much of the complexity of developing your own ACL approach. The
+ interfaces and classes detailed above provide a scalable, customisable
+ ACL solution that is decoupled from your application code. Whilst the
+ reference documentation may suggest complexity, the basic
+ implementation is able to support most typical applications
+ out-of-the-box.
+
+
+
+
+ Filters
+
+
+ Overview
+
+ The Acegi Security System for Spring uses filters extensively.
+ Each filter is covered in detail in a respective section of this
+ document. This section includes information that applies to all
+ filters.
+
+
+
+ FilterToBeanProxy
+
+ Most filters are configured using the
+ FilterToBeanProxy. An example configuration from
+ web.xml follows:
+
+ <filter>
+ <filter-name>Acegi HTTP Request Security Filter</filter-name>
+ <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
+ <init-param>
+ <param-name>targetClass</param-name>
+ <param-value>net.sf.acegisecurity.ClassThatImplementsFilter</param-value>
+ </init-param>
+</filter>
+
+ Notice that the filter in web.xml is actually
+ a FilterToBeanProxy, and not the filter that will
+ actually implements the logic of the filter. What
+ FilterToBeanProxy does is delegate the
+ Filter'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
+ javax.servlet.Filter.
+
+ The FilterToBeanProxy only requires a single
+ initialization parameter, targetClass or
+ targetBean. The targetClass
+ parameter locates the first object in the application context of the
+ specified class, whilst targetBean locates the
+ object by bean name. Like standard Spring web applications, the
+ FilterToBeanProxy accesses the application context
+ via
+ WebApplicationContextUtils.getWebApplicationContext(ServletContext),
+ so you should configure a ContextLoaderListener in
+ web.xml.
+
+
+
+ Filter Ordering
+
+ The order that filters are defined in web.xml
+ is important.
+
+ Irrespective of which filters you are actually using, the order
+ of the <filter-mapping>s should be as
+ follows:
+
+
+
+ Acegi Channel Processing Filter
+ (ChannelProcessingFilter)
+
+
+
+ Acegi Authentication Processing Filter
+ (AuthenticationProcessingFilter)
+
+
+
+ Acegi CAS Processing Filter
+ (CasProcessingFilter)
+
+
+
+ Acegi HTTP BASIC Authorization Filter
+ (BasicProcessingFilter)
+
+
+
+ Acegi Security System for Spring Auto Integration Filter
+ (AutoIntegrationFilter)
+
+
+
+ Acegi HTTP Request Security Filter
+ (SecurityEnforcementFilter)
+
+
+
+ All of the above filters use
+ FilterToBeanProxy, which is discussed in the
+ previous section.
+
+ If you're using SiteMesh, ensure the Acegi Security filters
+ execute before the SiteMesh filters are called. This enables the
+ ContextHolder to be populated in time for use by
+ SiteMesh decorators.
+
+
+
+
+ Contacts Sample Application
+
+ Included with the Acegi Security System for Spring 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).
+
+ The Contacts sample application includes two deployable versions:
+ contacts.war is configured with the HTTP Session
+ Authentication approach, and does not use Container Adapters. The
+ contacts-container-adapter.war is configured to use a
+ Container Adapter. If you're just wanting to see how the sample
+ application works, please use contacts.war as it does
+ not require special configuration of your container.
+
+ If you are going to use the
+ contacts-container-adapter.war version, first
+ configure your container as described in the Container Adapters section
+ of this chapter. Do not modify acegisecurity.xml. It
+ contains a very basic in-memory authentication configuration that is
+ compatible with the sample application.
+
+ To deploy, simply copy the relevant
+ contacts.war or
+ contacts-container-adapter.war file from the Acegi
+ Security System for Spring distribution into your container’s
+ webapps directory.
+
+ After starting your container, check the application can load.
+ Visit http://localhost:8080/contacts (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.
+
+ 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:
+
+
+ Context on ContextHolder is of type:
+ net.sf.acegisecurity.context.SecureContextImpl
+
+ The Context implements SecureContext.
+
+ Authentication object is of type:
+ net.sf.acegisecurity.adapters.PrincipalAcegiUserToken
+
+ Authentication object as a String:
+ net.sf.acegisecurity.adapters.PrincipalAcegiUserToken@e9a7c2:
+ Username: marissa; Password: [PROTECTED]; Authenticated: true; Granted
+ Authorities: ROLE_TELLER, ROLE_SUPERVISOR
+
+ Authentication object holds the following granted
+ authorities:
+
+ ROLE_TELLER (getAuthority(): ROLE_TELLER)
+
+ ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR)
+
+ SUCCESS! Your [container adapter|web filter] appears to be
+ properly configured!
+
+
+ If you receive a different message, and deployed
+ contacts-container-adapter.war, check you have
+ properly configured your Container Adapter. Refer to the instructions
+ provided above.
+
+ 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 belonging to the
+ currently logged on user are displayed, and only users with
+ ROLE_SUPERVISOR are granted access to delete their
+ contacts. Behind the scenes, the
+ MethodSecurityInterceptor is securing the business
+ objects. If you're using contacts.war, the
+ FilterSecurityInterceptor is also securing the HTTP
+ requests. If using contacts.war, be sure to try
+ visiting http://localhost:8080/contacts/secure/super,
+ which will demonstrate access being denied by the
+ SecurityEnforcementFilter.
+
+ The Contacts sample application also include a
+ client directory. Inside you will find a small
+ application that queries the backend business objects using the Hessian
+ and Burlap protocols. This demonstrates how to use the Acegi Security
+ System for Spring for authentication with Spring remoting protocols. To
+ try this client, ensure your servlet container is still running the
+ Contacts sample application, and then execute client marissa
+ marissa koala. The command-line parameters respectively
+ represent the owner of the contacts to extract, the username to use, and
+ the password to use. Note that you may need to edit
+ client.properties to use a different target URL. To
+ see that security does indeed work, try running client scott
+ marissa koala, which will try to obtain
+ scott's contacts when authenticating as
+ marissa. To see it work properly, use client
+ scott scott wombat.
+
+ Please note the sample application's client
+ does not currently support CAS. You can still give it a try, though, if
+ you're ambitious: try client scott _cas_stateless_
+ YOUR-SERVICE-TICKET-ID-FOR-SCOTT.
+
+
+
+ Become Involved
+
+ We welcome you to become involved in the Acegi Security System for
+ Spring 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, or
+ simply making suggestions.
+
+ SourceForge provides CVS services for the project, allowing
+ anybody to access the latest code. If you wish to contribute new code,
+ please observe the following requirements. These exist to maintain the
+ quality and consistency of the project:
+
+
+
+ Run the Ant format task (or use a suitable
+ IDE plug-in) to convert your code into the project's consistent
+ style
+
+
+
+ Ensure your code does not break any unit tests (run the Ant
+ tests target)
+
+
+
+ Please use the container integration test system to test your
+ code in the project's officially supported containers
+
+
+
+ When writing a new container adapter, expand the container
+ integration test system to properly test it
+
+
+
+ If you have added new code, please provide suitable unit tests
+ (use ant clover.html to view coverage)
+
+
+
+ Join the acegisecurity-developer and acegisecurity-cvs mailing
+ lists so you're in the loop
+
+
+
+ Use CamelCase
+
+
+
+ Add a CVS $Id: index.xml,v 1.3 2004/04/02 21:12:25
+ fbos Exp $ tag to the JavaDocs for any new class you
+ create
+
+
+
+ Mentioned above is our container integration test system, which
+ aims to test the Acegi Security System for Spring container adapters
+ with current, production versions of each container. Some containers
+ might not be supported due to difficulties with starting or stopping the
+ container within an Ant target. You will need to download the container
+ release files as specified in the integration test
+ readme.txt file. These files are intentionally
+ excluded from CVS due to their large size.
+
+
+
+ Further Information
+
+ Questions and comments on the Acegi Security System for Spring are
+ welcome. Please use the Spring Community Forum web site at
+ http://forum.springframework.org. You're also welcome
+ to join the acegisecurity-developer mailing list. Our project home page
+ (where you can obtain the latest release of the project and access to
+ CVS, mailing lists, forums etc) is at
+ http://acegisecurity.sourceforge.net.
+
+
+
\ No newline at end of file
diff --git a/docbook/styles/fo/docbook.xsl b/docbook/styles/fo/docbook.xsl
new file mode 100644
index 0000000000..9a216e723d
--- /dev/null
+++ b/docbook/styles/fo/docbook.xsl
@@ -0,0 +1,488 @@
+
+
+
+
+
+
+]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copyright (c) 2004 -
+
+
+ ,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -5em
+ -5em
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Acegi Security System for Spring
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bold
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 1
+
+ 1
+
+
+
+
+
+ book toc
+
+
+
+ 2
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 0
+
+
+ 5mm
+ 10mm
+ 10mm
+
+ 15mm
+ 10mm
+ 0mm
+
+ 18mm
+ 18mm
+
+
+ 0pc
+
+
+
+
+ left
+ false
+
+
+ 11
+ 8
+
+
+ 1.4
+
+
+
+
+
+
+ 0.8em
+
+
+
+
+
+ 17.4cm
+
+
+
+ 4pt
+ 4pt
+ 4pt
+ 4pt
+
+
+
+ 0.1pt
+ 0.1pt
+
+
+
+
+ 1
+
+
+
+
+
+
+
+ left
+ bold
+
+
+ pt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.8em
+ 0.8em
+ 0.8em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+ 0.6em
+ 0.6em
+ 0.6em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+ 0.4em
+ 0.4em
+ 0.4em
+
+
+ pt
+
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+
+
+ bold
+
+
+ pt
+
+ false
+ 0.4em
+ 0.6em
+ 0.8em
+
+
+
+
+
+
+
+
+ pt
+
+
+
+
+ 1em
+ 1em
+ 1em
+
+
+ #444444
+ solid
+ 0.1pt
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+ 0.5em
+
+
+
+ 1
+
+ #F0F0F0
+
+
+
+
+
+ 0
+ 1
+
+
+ 90
+
+
+
+
+ '1'
+ &admon_gfx_path;
+
+
+
+
+
+ figure after
+ example before
+ equation before
+ table before
+ procedure before
+
+
+
+ 1
+
+
+
+ 0.8em
+ 0.8em
+ 0.8em
+ 0.1em
+ 0.1em
+ 0.1em
+
+
+
diff --git a/docbook/styles/html.css b/docbook/styles/html.css
new file mode 100644
index 0000000000..4c06929fc0
--- /dev/null
+++ b/docbook/styles/html.css
@@ -0,0 +1,168 @@
+A {
+ color: #003399;
+}
+
+A:active {
+ color: #003399;
+}
+
+A:visited {
+ color: #888888;
+}
+
+P, DL, DT, DD, BLOCKQUOTE {
+ color: #000000;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding-top: 0px;
+ /*border: 1px solid black;*/
+}
+
+OL, UL, P {
+ margin-top: 6px;
+ margin-bottom: 6px;
+}
+
+P, BLOCKQUOTE {
+ font-size: 90%;
+}
+
+P.releaseinfo {
+ font-size: 120%; font-weight: bold;
+ font-family: Arial, helvetica, sans-serif;
+ padding-top: 10px;
+}
+
+P.pubdate {
+ font-size: 120%; font-weight: bold;
+ font-family: Arial, helvetica, sans-serif;
+}
+
+td {
+ font-size: 80%;
+}
+
+
+TD, TH, SPAN {
+ color: #000000;
+}
+
+BLOCKQUOTE {
+ margin-right: 0px;
+}
+
+H1, H2, H3, H4, H5, H6 {
+ color: #000000;
+ font-weight:500;
+ margin-top:0px;
+ padding-top:14px;
+ font-family: Arial, helvetica, sans-serif;
+ margin-bottom: 0px;
+}
+
+H2.title {
+ font-weight:800;
+ margin-bottom: 8px;
+}
+
+H2.subtitle {
+ font-weight:800;
+ margin-bottom: 20px;
+}
+
+H3.author {
+ color: #000000;
+ font-weight:500;
+ margin-top:0px;
+ padding-top:0px;
+ font-family: Arial, helvetica, sans-serif;
+ margin-bottom: 0px;
+}
+
+TABLE {
+ border-collapse: collapse;
+ border-spacing:0;
+ border: 1px thin black;
+ empty-cells: hide;
+}
+
+TD {
+ padding: 4pt;
+}
+
+H1 {
+ font-size: 150%;
+}
+H2 {
+ font-size: 110%;
+}
+H3 {
+ font-size: 100%; font-weight: bold;
+}
+H4 {
+ font-size: 90%; font-weight: bold;
+}
+H5 {
+ font-size: 90%; font-style: italic;
+}
+H6 {
+ font-size: 100%; font-style: italic;
+}
+
+TT {
+ font-size: 90%;
+ font-family: "Courier New", Courier, monospace;
+ color: #000000;
+}
+
+.navheader, .navfooter {
+ background-color: #e4eff3;
+}
+
+PRE {
+ font-size: 90%;
+ padding: 5px;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #CCCCCC;
+ background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+ list-style: disc;
+}
+
+HR {
+ width: 100%;
+ height: 1px;
+ background-color: #CCCCCC;
+ border-width: 0px;
+ padding: 0px;
+ color: #CCCCCC;
+}
+
+.variablelist {
+ padding-top: 10;
+ padding-bottom:10;
+ margin:0;
+}
+
+/*(.itemizedlist, UL {
+ padding-top: 0;
+ padding-bottom:0;
+ margin:0;
+}*/
+
+.term {
+ font-weight:bold;
+}
+
+.mediaobject {
+ padding-top: 30px;
+ padding-bottom: 30px;
+}
+
+.legalnotice {
+ font-size: 70%;
+}
+
diff --git a/docbook/styles/html.xsl b/docbook/styles/html.xsl
new file mode 100644
index 0000000000..247cadcaee
--- /dev/null
+++ b/docbook/styles/html.xsl
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+]>
+
+
+
+
+
+
+
+ ../styles/html.css
+
+
+ 1
+ 0
+ 1
+ 0
+
+
+
+
+
+ book toc
+
+
+
+ 3
+
+
+
+
+ 1
+
+
+
+
+
+
+ 1
+ &callout_gfx_path;
+
+
+ 90
+
+
+
+
+ '1'
+ &admon_gfx_path;
+
+
+
+
+
+ figure after
+ example before
+ equation before
+ table before
+ procedure before
+
+
+
diff --git a/docbook/styles/html_chunk.xsl b/docbook/styles/html_chunk.xsl
new file mode 100644
index 0000000000..c6f12b557e
--- /dev/null
+++ b/docbook/styles/html_chunk.xsl
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+]>
+
+
+
+
+
+
+
+ '5'
+ '1'
+ ../styles/html.css
+
+
+ 1
+ 0
+ 1
+ 0
+
+
+
+
+
+ book toc
+
+
+
+ 3
+
+
+
+
+ 1
+
+
+
+
+
+
+ 1
+ &callout_gfx_path;
+
+
+ 90
+
+
+
+
+ '1'
+ &admon_gfx_path;
+
+
+
+
+
+ figure after
+ example before
+ equation before
+ table before
+ procedure before
+
+
+