Acegi Security System for Spring Reference Documentation 0.4 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. Whilst the Acegi Security System for Spring is not officially part of Spring, it is hoped this implementation will further discussion concerning the implementation of security capabilities within Spring itself. 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 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. High Level Design Key Components The Acegi Security System for Spring essentially comprises six key functional parts: An Authentication object which holds the principal, credentials and the authorities granted to the principal. 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. 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 two currently supported secure object types (MethodInvocation and FilterInterceptor) with complete transparency. Each of the six key parts is discussed in detail throughout this document. Supported Secure Objects The Acegi Security System for Spring currently supports two 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. Most Spring developers would already be familiar with these due to their use in transactions and other areas of Spring. The second 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. Future Work Over time it is hoped that the Spring remoting classes can be extended to support propagation of the Context between ContextHolders on the client and server. 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. Call a secure object-specific SecurityInterceptorCallback so that the request execution can proceed. 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 SecurityInterceptorCallback. 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. 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). The MethodSecurityInterceptor is configured as follows: <bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.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. FilterInvocation Security Interceptor To secure FilterInvocations, developers need to add a SecurityEnforcementFilter to their web.xml. A typical configuration example is provided below: <filter> <filter-name>Acegi HTTP Request Security Filter</filter-name> <filter-class>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</filter-class> <init-param> <param-name>appContextLocation</param-name> <param-value>web-filters-acegisecurity.xml</param-value> </init-param> <init-param> <param-name>loginFormUrl</param-name> <param-value>/acegilogin.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>Acegi HTTP Request Security Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> As shown above, an appContextLocation indicates the location of a Spring XML application context. In the example above, this file should be placed at the root of the web application's classpath (in the WEB-INF/classes directory). The loginFormUrl is where the filter will redirect the user's browser if they request a secure HTTP resource but they are not authenticated. If the user is authenticated, a "403 Forbidden" response will be returned to the browser. All paths are relative to the web application root. The SecurityEnforcementFilter will load the Spring XML application context expressed in the appContextLocation. It will expect to find in this application context a properly configured FilterSecurityInterceptor. The configuration of the FilterSecurityInterceptor is very similar to the MethodSecurityInterceptor: <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> 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 regular expression evaluation of the request URL. It works down the list in the order they are defined. Thus it is important that more specific regular expressions are defined higher in the list than less specific regular expressions. This is reflected in our example above, where the more specific /secure/super pattern appears higher than the less specific /super pattern. If they were reversed, the /super 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 regular 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 regular 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. 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. 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="ignorePasswordCase"><value>false</value></property> <property name="ignoreUsernameCase"><value>true</value></property> </bean> By default the DaoAuthenticationProvider does not require an exact match on usernames, but it does require an exact match on passwords. This behavior can be configured with the optional properties shown above. For a class to be able to provide the DaoAuthenticationProvider with access to an authentication repository, it must implement the AuthenticationDao interface: public User loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException; The User object holds basic information such as the username, password, granted authorities and whether the user is enabled or disabled. 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 in a new AuthenticationManager or AuthenticationProvider implementation if it were desired. 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. Of particular note is the database must return responses that treat the username as case insensitive, in order to comply with the AuthenticationDao contract. 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. 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, it 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. Although 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. Most authorization decision rules can be easily satisfied by writing an AccessDecisionVoter implementation and using either ConsensusBased, AffirmativeBased or UnanimousBased as the AccessDecisionManager. 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. Develolpers 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 design 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. Several alternatives are available for the first step. The two most supported approaches are HTTP Session Authentication, which uses the HttpSession object and filters to authenticate the user. The other is via Container Adapters, which allow supported web containers to perform the authentication themselves. HTTP Session Authentication is discussed below, whilst Container Adapters are discussed in a separate section. 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 as follows: <filter> <filter-name>Acegi Authentication Processing Filter</filter-name> <filter-class>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</filter-class> <init-param> <param-name>appContextLocation</param-name> <param-value>web-filters-acegisecurity.xml</param-value> </init-param> <init-param> <param-name>authenticationFailureUrl</param-name> <param-value>/acegilogin.jsp?login_error=1</param-value> </init-param> <init-param> <param-name>defaultTargetUrl</param-name> <param-value>/</param-value> </init-param> <init-param> <param-name>filterProcessUrl</param-name> <param-value>/j_acegi_security_check</param-value> </init-param> </filter> <filter-mapping> <filter-name>Acegi Authentication Processing Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> The appContextLocation specifies the location of a Spring XML application context. In the example above the root of the classpath is used, so the XML file should be placed in WEB-INF/classes. The AuthenticationProcessingFilter will load this application context, expecting to find a properly configured AuthenticationManager. It will use this AuthenticationManager to process 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 AuthenticationProcessingFilter.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 AuthenticationProcessingFilter.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 filter initialization 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. Well-Known Location Integration Once a web application has used either HTTP Session 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, 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.ui.AutoIntegrationFilter</filter-class> </filter> <filter-mapping> <filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 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 approach was developed, and is 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. 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 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 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 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 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. 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.
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) 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 direct comments to the Spring Users mailing list or ben.alex@acegi.com.au. Our project home page (where you can obtain the latest release of the project and access to CVS) is at http://acegisecurity.sourceforge.net.