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 + + +