diff --git a/changelog.txt b/changelog.txt index 9b2e006946..98d1560cc9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,25 @@ +Changes in version 0.4 (2004-04-03) +----------------------------------- + +* Added HTTP session authentication as an alternative to container adapters +* Added HTTP request security interceptor (offers considerable flexibility) +* Added security taglib +* Added Clover test coverage instrumentation (currently 97.2%) +* Added support for Catalina (Tomcat) 4.1.30 to in-container integration tests +* Added HTML test and summary reporting to in-container integration tests +* Updated JARs to Spring Framework release 1.0, with associated AOP changes +* Updated to Apache License version 2.0 +* Updated copyright with permission of past contributors +* Refactored unit tests to use mock objects and focus on a single class each +* Refactored many classes to enable insertion of mock objects during testing +* Refactored core classes to ease support of new secure object types +* Changed package layout to better describe the role of contained items +* Changed the extractor to extract additional classes from JBoss and Catalina +* Changed Jetty container adapter configuration (see reference documentation) +* Improved AutoIntegrationFilter handling of deployments without JBoss JARs +* Fixed case handling support in data access object authentication provider +* Documentation improvements + Changes in version 0.3 (2004-03-16) ----------------------------------- diff --git a/docs/reference/src/index.xml b/docs/reference/src/index.xml index 7fb3b9a9e1..4670ac8156 100644 --- a/docs/reference/src/index.xml +++ b/docs/reference/src/index.xml @@ -1,4 +1,4 @@ - + @@ -7,7 +7,7 @@ Reference Documentation - 0.3 + 0.4 @@ -65,6 +65,157 @@ 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 @@ -144,24 +295,108 @@ Security Interception - - Configuration + + All Secure Objects - The security architecture is implemented by placing a properly - configured SecurityInterceptor into the bean - context, and then chaining that SecurityInterceptor - into a business object. This chaining is accomplished using Spring’s - ProxyFactoryBean, as commonly used by many other - parts of Spring (refer to the security test cases and sample - application for examples). The SecurityInterceptor - is configured as follows: + 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: - <bean id="bankManagerSecurity" class="net.sf.acegisecurity.SecurityInterceptor"> + + + 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="methodDefinitionSource"> + <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 @@ -169,56 +404,66 @@ </property> </bean> - As shown above, the SecurityInterceptor is - configured with a reference to an + 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 SecurityInterceptor is also - configured with "configuration attributes" that apply to different - method signatures. A configuration attribute is simply a - ConfigAttribute instance that has special meaning - to an AccessDecisionManager and/or - RunAsManager. + 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 SecurityInterceptor can be configured - with configuration attributes in three ways. The first is via a - property editor and the bean context, which is shown above. The second - is via defining the configuration attributes in your source code using - Commons Attributes. The third is via writing your own - MethodDefinitionSource, although this is beyond the - scope of this document. Irrespective of the approach used, the - MethodDefinitionSource is responsible for returning - a ConfigAttributeDefinition object that contains - all of the configuration attributes associated with a single secure - method. + 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. - If using the 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. - SecurityConfig is a concrete implementation of - ConfigAttribute, and simply stores the - configuration attribute as a String. + 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 Commons Attributes approach, your bean context will - be configured differently: + 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="methodDefinitionSource" class="net.sf.acegisecurity.MethodDefinitionAttributes"> +<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.SecurityInterceptor"> +<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="methodDefinitionSource"><ref bean="methodDefinitionSource"/></property> + <property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/></property> </bean> - In addition, your source code will contain Commons Attributes - tags that refer to a concrete implementation of + 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 @@ -250,101 +495,144 @@ You might have noticed the validateConfigAttributes property in the above - SecurityInterceptor examples. When set to + MethodSecurityInterceptor examples. When set to true (the default), at startup time the - SecurityInterceptor will evaluate if the provided - configuration attributes are valid. It does this by checking each - configuration attribute can be processed by either 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 - Commons Attributes method of configuration, you should set + Jakarta Commons Attributes method of configuration, you should set validateConfigAttributes to false. - - Runtime Processing + + FilterInvocation Security Interceptor - At runtime the SecurityInterceptor has three - basic tasks: authenticate, authorize and perform any run-as - authentication replacement. It assesses the method pattern being - invoked to determine whether or not it is secure. A secure method - matches a method pattern defined with configuration attributes in the - bean context, whilst a public method is not defined in the bean - context. + 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> - If a public method is called, - SecurityInterceptor will make no effort to - authenticate, authorize or perform any run-as authentication - replacement for the request. However, should there be an - Authentication object in the - ContextHolder, it will have its authenticated - property set to false. Once this is handled, - invocation of the public method will proceed as normal. +<filter-mapping> + <filter-name>Acegi HTTP Request Security Filter</filter-name> + <url-pattern>/*</url-pattern> +</filter-mapping> - If a secure method is called, - SecurityInterceptor will need to extract an - Authentication object from the request context. As - discussed above, the SecurityInterceptor requires - the SecureContext interface be implemented on the - object contained in the ContextHolder. Once the - Authentication object is extracted from the - SecureContext, it will be passed to the - SecurityInterceptor’s - AuthenticationManager. + 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 AuthenticationManager will perform - authentication, throwing an AuthenticationException - if there is a problem. If successful, the - AuthenticationManager will return a populated - Authentication object, including the authorities - granted to the principal. SecurityInterceptor will - then call its AccessDecisionManager. + 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: - When the AccessDecisionManager is invoked by - the SecurityInterceptor, it will be passed - important information it may require to make an authorization - decision. This includes details of the secure method that is being - invoked, the authenticated principal, and the - ConfigAttributeDefinition (the collection of - configuration attributes associated with the secure method). If - authorization fails, the AccessDecisionManager will - throw an AccessDeniedException. If successful, the - SecurityInterceptor will then call the - RunAsManager. + <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 the AccessDecisionManager, the - RunAsManager is called with details of the secure - method being invoked, the authenticated principal, and the - ConfigAttributeDefinition. The - RunAsManager can then choose to return a - replacement Authentication object that should be - used for the request. If a replacement - Authentication object is returned, the - SecurityInterceptor will update the - ContextHolder for the duration of the method - invocation, returning to the original - Authentication object after the method has been - invoked. - - - - Putting it into Context - - The above briefly outlines that the - AuthenticationManager, + Like any other security interceptor, the + FilterSecurityInterceptor requires a reference to + an AuthenticationManager, AccessDecisionManager and - RunAsManager perform the bulk of the security - decision making. The SecurityInterceptor simply - coordinates the method invocation and stores the configuration - attributes that are relevant to different methods. It also coordinates - the temporary replacement of the Authentication - object as a consequence of RunAsManager responses. - The way AuthenticationManager, - AccessDecisionManager and - RunAsManager operate is discussed in detail - below. + 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. @@ -371,7 +659,8 @@ UsernamePasswordAuthenticationToken allows a username and password to be presented as the principal - and credentials respectively. + and credentials respectively. It is also what is created by the + HTTP Session Authentication system. @@ -409,9 +698,10 @@ Authentication Manager As discussed in the Security Interception section, the - SecurityInterceptor extracts the + AbstractSecurityInterceptor extracts the Authentication object from the - SecureContext. This is then passed to an + SecureContext in the + ContextHolder. This is then passed to an AuthenticationManager. The AuthenticationManager interface is very simple: @@ -426,7 +716,8 @@ GrantedAuthority objects. The SecurityInterceptor places the populated Authentication object back in the - SecureContext, overwriting the original + SecureContext in the + ContextHolder, overwriting the original Authentication object. The AuthenticationException has a number of @@ -441,13 +732,13 @@ 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 in the Acegi + 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: @@ -456,6 +747,7 @@ <property name="providers"> <list> <ref bean="daoAuthenticationProvider"/> + <ref bean="someOtherAuthenticationProvider"/> </list> </property> </bean> @@ -471,7 +763,7 @@ object. Note the ProviderManager may throw a - ProviderNotFoundException (subclass of + ProviderNotFoundException (a subclass of AuthenticationException) if it none of the registered AuthenticationProviders can validate the Authentication object. @@ -489,7 +781,9 @@ 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. + required for calling a given method. You definitely would not + register this AuthenticationProvider on a + production system. @@ -497,27 +791,32 @@ authenticate a UsernamePasswordAuthenticationToken by accessing an authentication respository via a data access - object. This is discussed further below. + 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. + 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. + 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 @@ -557,12 +856,15 @@ 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. Such functionality could be easily provided in a new + 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. + AuthenticationProvider implementation if it were + desired. - + In-Memory Authentication Whilst it is easy to use the @@ -570,7 +872,7 @@ 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 bean context itself using the + authentication repository in the application context itself using the InMemoryDaoImpl: <bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl"> @@ -594,12 +896,12 @@ 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 or no 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 @@ -614,7 +916,6 @@ <property name="password"><value></value></property> </bean> -<!-- Data access object which stores authentication information --> <bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"> <property name="dataSource"><ref bean="dataSource"/></property> </bean> @@ -622,7 +923,10 @@ 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. + 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 @@ -631,27 +935,9 @@ 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. - - As discussed further in the Container Adapters section, most - authentication providers that perform actual authentication are - configured within a container adapter bean context typically called - acegisecurity.xml. This file by default uses the - in-memory DAO authentication provider. The Acegi Security System for - Spring includes an alternative configuration file named - acegisecurity-jdbc.xml, which uses the JDBC DAO - authentication provider. To use a JDBC authentication repository, - simply copy this file over the existing - acegisecurity.xml (or other name) being used by - your container. Alternatively, leave the name as - acegisecurity-jdbc.xml and modify your container - configuration file to refer to - acegisecurity-jdbc.xml. You will also need to copy - the relevant JDBC driver library to your container's - lib directory. If you are using Hypersonic SQL, - copy the hsqldb.jar file. - + Authentication Recommendations With the heavy use of interfaces throughout the authentication @@ -665,9 +951,8 @@ Use the - UsernamePasswordAuthenticationToken or an - AuthByContainer implementation where - possible. + UsernamePasswordAuthenticationToken + implementation where possible. @@ -679,6 +964,15 @@ 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 @@ -701,15 +995,15 @@ 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 + 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. @@ -747,92 +1041,104 @@ user-specified String to be converted into a GrantedAuthority. All AuthenticationProviders included with the security - architecture used GrantedAuthorityImpl to populate + architecture use GrantedAuthorityImpl to populate the Authentication object. - + Access Decision Managers The AccessDecisionManager is called by the - SecurityInterceptor and is responsible for making - final access control decisions. The - AccessDecisionManager interface contains two + AbstractSecurityInterceptor and is responsible for + making final access control decisions. The + AccessDecisionManager interface contains three methods: - public void decide(Authentication authentication, MethodInvocation invocation, ConfigAttributeDefinition config) throws AccessDeniedException; -public boolean supports(ConfigAttribute attribute); + 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 - MethodInvocation enables those arguments contained - in the intercepted method call to be inspected. For example, if a - Customer argument was passed in the intercepted - method call, this could be extracted from the - MethodInvocation and used in making an access - control decision. Implementations are expected to throw an + 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 SecurtyInterceptor at startup time to - determine if the AccessDecisionManager can process - the passed ConfigAttribute. + 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 an - AccessDecisionManager implementation that is based - on voting. Using this approach, a series 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 two + The AccessDecisionVoter interface has three methods: - public int vote(Authentication authentication, MethodInvocation invocation, ConfigAttributeDefinition config); -public boolean supports(ConfigAttribute attribute); + 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 + 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 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 + 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 will deny access if there - was any ACCESS_DENIED result. Like the other - implementations, there is a parameter that controls the behaviour if - all voters abstain. + 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 would have a - veto effect. + 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 @@ -853,35 +1159,132 @@ public boolean supports(ConfigAttribute attribute); It is possible to implement a custom AccessDecisionVoter. Several examples are provided in the Acegi Security System for Spring unit tests, including - BankSecurityVoter and XVoter. - The BankSecurityVoter abstains from voting - decisions where the BANKSECURITY_CUSTOMER + 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 account number - subject of the method call. It votes to grant access if the account - number matches a GrantedAuthority.getAuthority() of - ACCOUNT_xxxx where xxxx is the - account number subject of the method call. All of this is achieved - with relatively few lines of code and demonstrates the flexibility of - the authorization model. - - Note that an AccessDecisionManager or - AccessDecisionVoter can also support complex - GrantedAuthority implementations that cannot - represent themselves as a String via the - getAuthority() method. In our - BankSecurityVoter example, we could have it ignore - the String representations of - GrantedAuthority objects but instead processed any - AccountHolderGrantedAuthority objects. This complex - granted authority could have conveyed more information than simply an - account number, such as the maximum amount the principal is permitted - to deposit. The BankSecurityVoter could then detect - a deposit value via the MethodInvocation and grant - or deny access accordingly. + 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 @@ -903,172 +1306,70 @@ public boolean supports(ConfigAttribute attribute); Most authorization decision rules can be easily satisfied by writing an AccessDecisionVoter implementation - and using either ConsensusBased or - AffirmativeBased as the + and using either ConsensusBased, + AffirmativeBased or + UnanimousBased as the AccessDecisionManager. - - - Authorization Tag Library - - The Acegi Security System for Spring comes bundled with a - JSP tag library that eases JSP writing. - - This library simply wraps some bits of Java code, for - easy reuse. The tag library also allows the JSP developer to - determine if a principal has, doesn't have or has any of a - specified set of roles. - - - 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 pricipal 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 to 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> - - - You will also need to extract the authz.tld file from - the acegi-security-taglib.jar file. Use a regular Zip tool, - or use 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 it's - body. - - - ifAnyGranted: Any of the - listed roles must be granted for the tag to output - it's body. - - - ifNotGranted: None of the - listed roles must be granted for the tag to output - it's 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, they all 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. - - One last item: the tag verifies the authorizations in a - specific order: first ifNotGranted, then - ifAllGranted, and finally, - ifAnyGranted. - - - This might or might not be important to you, depending - on how your authorization scheme is defined, but it allows you - to express concepts like: principal is a SUPERVISOR, but not - a NEWBIE_SUPERVISOR. - - - + Run-As Authentication Replacement - + Purpose - The SecurityInterceptor is able to temporarily replace the - Authentication object in the - ContextHolder during a method invocation. This only - occurs if the original Authentication object was - successfully processed by the AuthenticationManager - and AccessDecisionManager. The + 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 method invocation. + Authentication object, if any, that should be used + during the SecurityInterceptorCallback. By temporarily replacing the Authentication - object during a method invocation, the method 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 + 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, MethodInvocation invocation, ConfigAttributeDefinition config); -public boolean supports(ConfigAttribute attribute); + 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 SecurityInterceptor as part of its startup - validation of configuration attributes. + 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 + 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 @@ -1084,14 +1385,14 @@ public boolean supports(ConfigAttribute attribute); 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 + probably via delegation to a suitable + AuthenticationProvider. The RunAsImplAuthenticationProvider performs such - authentication. It simply accepts as valid whatever - RunAsUserToken is presented. + authentication. It simply accepts as valid any + RunAsUserToken presented. To ensure malicious code does not create a - RunAsUserToken and presents it for guaranteed + RunAsUserToken and present it for guaranteed acceptance by the RunAsImplAuthenticationProvider, the hash of a key is stored in all generated tokens. The RunAsManagerImpl and @@ -1112,77 +1413,171 @@ public boolean supports(ConfigAttribute attribute); - - Container Adapters + + User Interfacing with the ContextHolder - - Overview + + Purpose - A very large proportion of Spring applications are web-based. - The Acegi Security System for Spring supports integration with - containers that host such 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 bean-level - security capabilities provided by the Acegi Security System for - Spring. + 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 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 often needs - to return a container-compatible user object. + 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: - The adapter is instantiated by the container and is defined in a - container-specific configuration file. The adapter then loads a Spring - bean context which defines the normal authentication manager settings, - such as the authentication providers that can be used to authenticate - the request. The bean context is usually named - acegisecurity.xml and is placed in a - container-specific location. + + + Actually authenticate the user and place the resulting + Authentication object in a "well-known + location". + - The Acegi Security System for Spring currently supports Jetty, - Catalina (Tomcat), JBoss and Resin. Additional container adapters can - easily be written. + + 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. - - Filter Integration + + HTTP Session Authentication - Web applications wishing to use container adapters should define - the standard <security-constraint> and - <login-config> entries in their - web.xml file. These will cause the container - authentication to occur, which will delegate to the Acegi Security - System for Spring provided adapter. + 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: - The adapter will return a container-compatible user object that - also implements the Authentication interface. The - container then makes this returned user object available from a - container-specific well-known location. + <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 finalise the adapter integration. These classes are - standard filters, and at the start of each request they will attempt - to extract the Authentication object from the - container's well-known location. The Authentication - object will then be associated with the + 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 - be removed when the request is finished. Three concrete subclasses of + 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. It extracts the authentication - information from + with Catalina, Jetty and Resin Container Adapters. It extracts + the authentication information from HttpServletRequest.getUserPrincipal(). - JbossIntegrationFilter is used with - JBoss. It extracts the authentication from + JbossIntegrationFilter is used with the + JBoss Container Adapter. It extracts the authentication from java:comp/env/security/subject. @@ -1190,11 +1585,24 @@ public boolean supports(ConfigAttribute attribute); 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 container-specific + 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 @@ -1206,14 +1614,57 @@ public boolean supports(ConfigAttribute attribute); 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 SecurityInterceptor. The + 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. @@ -1239,14 +1690,14 @@ public boolean supports(ConfigAttribute attribute); authentication using providers such as DaoAuthenticationProvider, returning an AuthByAdapter instance that contains a hash code of - the key. Later, when an application calls a - SecurityInterceptor managed bean, the - AuthByAdapter instance in the + 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 bean context, as the only type of + application-specific application context, as the only type of Authentication instance that will be presented by the application is from the container adapter. @@ -1258,12 +1709,13 @@ public boolean supports(ConfigAttribute attribute); configured. - + Catalina (Tomcat) Installation - The following was tested with Jakarta Tomcat 5.0.19. We - automatically test the following directions using our container - integration test system and this version of Catalina (Tomcat). + 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. @@ -1307,9 +1759,19 @@ public boolean supports(ConfigAttribute attribute); 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 @@ -1328,7 +1790,7 @@ public boolean supports(ConfigAttribute attribute); <New class="net.sf.acegisecurity.adapters.jetty.JettyAcegiUserRealm"> <Arg>Spring Powered Realm</Arg> <Arg>my_password</Arg> - <Arg>/etc/acegisecurity.xml</Arg> + <Arg>etc/acegisecurity.xml</Arg> </New> </Arg> </Call> @@ -1365,7 +1827,7 @@ public boolean supports(ConfigAttribute attribute); Realm"). - + JBoss Installation The following was tested with JBoss 3.2.3. We automatically test @@ -1423,7 +1885,7 @@ public boolean supports(ConfigAttribute attribute); </jboss-web> - + Resin Installation The following was tested with Resin 3.0.6. @@ -1485,27 +1947,40 @@ public boolean supports(ConfigAttribute attribute); - Sample Application + 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. + provided by the system (and confirm your Container Adapter is properly + configured if you're using one). - To install, 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. Next, copy the contacts.war file from - the Acegi Security System for Spring distribution into your container’s + 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). 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. + 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 @@ -1533,21 +2008,28 @@ public boolean supports(ConfigAttribute attribute); ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR) - SUCCESS! Your container adapter appears to be properly - configured! + SUCCESS! Your [container adapter|web filter] appears to be + properly configured! - If you receive a different message, check you have properly - configured your container adapter. Refer to the instructions provided - above. + 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 SecurityInterceptor - is securing the business objects. + 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. @@ -1566,8 +2048,9 @@ public boolean supports(ConfigAttribute attribute); - Run the Ant format task to convert your - code into the project's consistent style + Run the Ant format task (or use a suitable + IDE plug-in) to convert your code into the project's consistent + style @@ -1586,13 +2069,14 @@ public boolean supports(ConfigAttribute attribute); - If you have added new code, please provide suitable unit - tests + If you have added new code, please provide suitable unit tests + (use ant clover.html to view coverage) - Add a CVS $Id$ tag to the JavaDocs for any - new class you create + 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