diff --git a/doc/docbook/acegi.xml b/doc/docbook/acegi.xml index 48914fe12e..44940815e2 100644 --- a/doc/docbook/acegi.xml +++ b/doc/docbook/acegi.xml @@ -106,12 +106,16 @@ Portable Runtime Project versioning guidelines, available from http://apr.apache.org/versioning.html. - Some minor improvements are currently intended prior to the - 1.0.0 release, although each of these represent additional - functionality that will in no way modify the project's central - interfaces or classes. Users of Acegi Security System for Spring - should therefore be comfortable depending on the current version of - the project in their applications. + We are now at release 0.9.0, and a lot of effort has been made + to implement all non-backward compatible changes either in or before + this release. Some minor improvements are currently intended to the + 1.0.0 release, although they will in no way modify the project's + central interfaces or classes. Users of Acegi Security System for + Spring should therefore be comfortable depending on the current + version of the project in their applications. Please note that we will + be changing the package name prefix in the 1.0.0 release, but this + should be a simple "find and replace" type operation in your + code. @@ -143,7 +147,7 @@ - A ContextHolder which holds the + A SecurityContextHolder which holds the Authentication object in a ThreadLocal-bound object. @@ -335,10 +339,13 @@ SecureContext defined an interface used for storage of the Authentication object. The ContextHolder was a ThreadLocal. - This was removed from 0.9.0 after discussion with other Spring - developers for the sake of consistency. See for example - http://article.gmane.org/gmane.comp.java.springframework.devel/8290. - This history is mentioned as the long period + A fuller discussion of the ThreadLocal usage with + Acegi Security follows in this document. + ContextHolder and SecureContext + was removed from 0.9.0 after discussion with other Spring developers + for the sake of consistency. See for example + http://article.gmane.org/gmane.comp.java.springframework.devel/8290 + and JIRA task SEC-77. This history is mentioned as the long period ContextHolder was used will likely mean that certain documentation you encounter concerning Acegi Security might still refer to ContextHolder. Generally you can @@ -432,7 +439,7 @@ Pass the Authentication object to the AuthenticationManager, update the - ContextHolder with the response. + SecurityContextHolder with the response. @@ -450,7 +457,7 @@ If the RunAsManager returns a new Authentication object, update the - ContextHolder with it. + SecurityContextHolder with it. @@ -461,7 +468,7 @@ If the RunAsManager earlier returned a new Authentication object, update the - ContextHolder with the + SecurityContextHolder with the Authentication object that was previously returned by the AuthenticationManager. @@ -1061,8 +1068,8 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { 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 + SecurityContext in the + SecurityContextHolder. This is then passed to an AuthenticationManager. The AuthenticationManager interface is very simple: @@ -1077,8 +1084,8 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { GrantedAuthority objects. The SecurityInterceptor places the populated Authentication object back in the - SecureContext in the - ContextHolder, overwriting the original + SecurityContext in the + SecurityContextHolder, overwriting the original Authentication object. The AuthenticationException has a number of @@ -1133,6 +1140,19 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { registered AuthenticationProviders can validate the Authentication object. + The ProviderManager also has several other + important functions. It integrates with concurrent session handling + supoprt, and it also converts any exceptions thrown by an + AuthenticationProvider and publishes a suitable + event. The events that are published are located in the + net.sf.acegisecurity.event.authentication package + and advanced users can map different exceptions to different events by + configuring the ProviderManager.exceptionMappings + property (generally this is not required and the default event + propagation is appropriate - especially as events will simply be + ignored if you don't have an ApplicationListener + configured in the ApplicationContext). + Several AuthenticationProvider implementations are provided with the Acegi Security System for Spring: @@ -1195,6 +1215,55 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { + + Concurrent Session Support + + Acegi Security is able to stop the same principal authenticating + to the same web application multiple times concurrently. Put + differently, you can stop user "Batman" from logging into a web + application twice at the same time. + + To use concurrent session support, you'll need to add the + following to web.xml: + + <listener> + <listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class> +</listener> + + In addition, you will need to add the + net.sf.acegisecurity.concurrent.ConcurrentSessionFilter + to your FilterChainProxy. The + ConcurrentSessionFilter requires only one property, sessionRegistry, + which generally points to an instance of + SessionRegistryImpl. + + The web.xml + HttpSessionEventPublisher causes an + ApplicationEvent to be published to the Spring + ApplicationContext every time a + HttpSession commences or terminates. This is + critical, as it allows the SessionRegistryImpl to + be notified when a session ends. + + You will also need to wire up the + ConcurrentSessionControllerImpl and refer to it + from your ProviderManager bean: + + <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"> + <property name="providers"> + <!-- your providers go here --> + </property> + <property name="sessionController"><ref bean="concurrentSessionController"/></property> +</bean> + +<bean id="concurrentSessionController" class="net.sf.acegisecurity.concurrent.ConcurrentSessionControllerImpl"> + <property name="maxSessions"><value>1</value></property> + <property name="sessionRegistry"><ref local="sessionRegistry"/></property> +</bean> + +<bean id="sessionRegistry" class="net.sf.acegisecurity.concurrent.SessionRegistryImpl"/> + + Data Access Object Authentication Provider @@ -1325,89 +1394,6 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { context. - - Event Publishing - - The DaoAuthenticationProvider automatically - obtains the ApplicationContext it is running in at - startup time. This allows the provider to publish events through the - standard Spring event framework. Three types of event messages are - published: - - - - AuthenticationSuccessEvent is published - when an authentication request is successful. - - - - AuthenticationFailureDisabledEvent is - published when an authentication request is unsuccessful because - the returned UserDetails is disabled. This is - normally the case when an account is locked. - - - - AuthenticationFailureAccountExpiredEvent - is published when an authentication request is unsuccessful - because the returned UserDetails indicates the - account has expired. Some applications may wish to distinguish - between an account being disabled and expired. - - - - AuthenticationFailureCredentialsExpiredEvent - is published when an authentication request is unsuccessful - because the returned UserDetails indicates the - account's credentials have expired. Some applications may wish to - expire the credentials if, for example, a password is not changed - with sufficient regularity. - - - - AuthenticationFailureUsernameNotFoundEvent - is published when an authentication request is unsuccessful - because the AuthenticationDao could not locate - the UserDetails. - - - - AuthenticationFailurePasswordEvent is - published when an authentication request is unsuccessful because - the presented password did not match that in the - UserDetails. - - - - Each event contains two objects: the - Authentication object that represented the - authentication request, and the UserDetails object - that was found in response to the authentication request (clearly the - latter will be a dummy object in the case of - AuthenticationFailureUsernameNotFoundEvent). The - Authentication interface provides a - getDetails() method which often includes - information that event consumers may find useful (eg the TCP/IP - address that the authentication request originated from). - - As per standard Spring event handling, you can receive these - events by adding a bean to the application context which implements - the ApplicationListener interface. Included with - Acegi Security is a LoggerListener class which - receives these events and publishes their details to Commons Logging. - Refer to the JavaDocs for LoggerListener for - details on the logging priorities used for different message - types. - - This event publishing system enables you to implement account - locking and record authentication event history. This might be of - interest to application users, who can be advised of the times and - source IP address of all unsuccessful password attempts (and account - lockouts) since their last successful login. Such capabilities are - simple to implement and greatly improve the security of your - application. - - In-Memory Authentication @@ -1443,6 +1429,14 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { 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. + + InMemoryDaoImpl also offers a + setUserProperties(Properties) method, which allows + you to externalise the java.util.Properties in + another Spring configured bean or an external properties file. This + might prove useful for simple applications that have a larger number + of users, or deployment-time configuration changes, but do not wish to + use a full database for authentication details. @@ -1474,77 +1468,6 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { customisation of the SQL statements. You may also subclass the JdbcDaoImpl if further customisation is necessary. Please refer to the JavaDocs for details. - - The Acegi Security System for Spring ships with a Hypersonic SQL - instance that has the required authentication information and sample - data already populated. To use this server, simply execute the - server.bat or server.sh script - included in the distribution. This will load a new database server - instance that will service requests made to the URL indicated in the - bean context configuration shown above. - - - - Concurrent Session Support - - Acegi Security is able to stop the same principal authenticating - to the same web application multiple times concurrently. Put - differently, you can stop user "Batman" from logging into a web - application twice at the same time. - - To use concurrent session support, you'll need to add the - following to web.xml: - - <listener> - <listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class> -</listener> - - The above code causes an ApplicationEvent to - be published to the Spring ApplicationContext every - time a HttpSession commences or terminates. This is - critical, as it allows the - ConcurrentSessionControllerImpl to be notified when - a session ends. Next up you'll need to wire the - ConcurrentSessionControllerImpl into your existing - ProviderManager: - - <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"> - <property name="providers"> - <!-- your providers go here --> - </property> - <property name="sessionController"><ref bean="concurrentSessionController"/></property> -</bean> - -<bean id="concurrentSessionController" class="net.sf.acegisecurity.providers.ConcurrentSessionControllerImpl"> - <property name="maxSessions"><value>1</value></property> -</bean> - - Ensure you do not in-line the - ConcurrentSessionControllerImpl when declaring it - in your XML. This is important, as it appears that in-lined bean - declarations do not receive ApplicationEvents. - - The ConcurrentSessionControllerImpl relies - heavily on the - Authentication.getPrincipal().equals() method. If - you are using a custom Authentication object, - please keep this in mind. In order for the - ConcurrentSessionControllerImpl to release a given - HttpSession, and thus let the user log in to a new - HttpSession, the existing - HttpSession must be invalidated. For example, if - "Batman" logs into the web application, checks for crimes being - commited, and the just closes his browser with out "logging out", he - will not be able to log back in until his - HttpSession is timed out by the server (and a - corresponding ApplicationEvent is published via - HttpSessionEventPublisher to the - ConcurrentSessionControllerImpl). You would have to - look at your container's documentation to determine the default - timeout period. You can also configure the session timeout in your - web.xml:<session-config> - <session-timeout>30</session-timeout> -</session-config> @@ -2165,23 +2088,20 @@ public boolean supports(Class clazz); AuthenticationTag AuthenticationTag is used to simply output - the current principal to the web page. + a property of the current principal's + Authentication.getPrincipal() object to the web + page. The following JSP fragment illustrates how to use the AuthenticationTag: - <authz:authentication operation="principal"/> + <authz:authentication operation="username"/> - This tag would cause the principal's name to be output. The - taglib properly supports the various types of principals that can - exist in the Authentication object, such as a - String or UserDetails - instance. - - The "operation" attribute must always be "principal". This may - be expanded in the future, such as obtaining other - Authentication-related properties such as email - address or telephone numbers. + This tag would cause the principal's name to be output. Here + we are assuming the Authentication.getPrincipal() + is a UserDetails object, which is generally the + case when using the typical + DaoAuthenticationProvider. @@ -2377,8 +2297,8 @@ public boolean supports(Class clazz); The AbstractSecurityInterceptor is able to temporarily replace the Authentication object in - the SecureContext and - ContextHolder during the + the SecurityContext and + SecurityContextHolder during the SecurityInterceptorCallback. This only occurs if the original Authentication object was successfully processed by the AuthenticationManager and @@ -2472,14 +2392,14 @@ public boolean supports(Class clazz); - User Interfacing with the ContextHolder + User Interfacing with the SecurityContextHolder Purpose Everything presented so far assumes one thing: the - ContextHolder is populated with a valid - SecureContext, which in turn contains a valid + SecurityContextHolder is populated with a valid + SecurityContext, which in turn contains a valid Authentication object. Developers are free to do this in whichever way they like, such as directly calling the relevant objects at runtime. However, several classes have been provided to @@ -2491,16 +2411,20 @@ public boolean supports(Class clazz); processing mechanism is solely concerned with received an authentication request from the principal, testing if it seems valid, and if so, placing the authentication request token onto the - ContextHolder. Of course, if the authentication request is invalid, - the authentication processing mechanism is responsible for informing - the principal in whatever way is appropriate to the protocol. + SecurityContextHolder. Of course, if the + authentication request is invalid, the authentication processing + mechanism is responsible for informing the principal in whatever way + is appropriate to the protocol. - Recall the HttpSessionContextIntegrationFilter (discussed in the - context section) is responsible for storing the ContextHolder contents - between invocations. This means no authentication processing mechanism - need ever interact directly with HttpSession. Indeed - HttpSessionContextIntegrationFilter has been designed to minimise the - unnecessary creation of HttpSessions, as might occur when using Basic + Recall the + HttpSessionContextIntegrationFilter (discussed in + the context section) is responsible for storing the + SecurityContextHolder contents between invocations. + This means no authentication processing mechanism need ever interact + directly with HttpSession. Indeed + HttpSessionContextIntegrationFilter has been + designed to minimise the unnecessary creation of + HttpSessions, as might occur when using Basic authentication for example. There are several authentication processing mechanisms included @@ -2567,12 +2491,12 @@ public boolean supports(Class clazz); If authentication is successful, the resulting Authentication object will be placed into the - ContextHolder. + SecurityContextHolder. - Once the ContextHolder 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 + Once the SecurityContextHolder has been + updated, the browser will need to be redirected to the target URL. The + target URL is usually indicated by the HttpSession + attribute specified by AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY. This attribute is automatically set by the SecurityEnforcementFilter when an @@ -2626,7 +2550,7 @@ public boolean supports(Class clazz); 401 response with a suitable header to retry HTTP Basic authentication. If authentication is successful, the resulting Authentication object will be placed into the - ContextHolder. + SecurityContextHolder. If the authentication event was successful, or authentication was not attempted because the HTTP header did not contain a supported @@ -2747,8 +2671,8 @@ key: A private key to prevent modification of the nonce token Like BasicAuthenticationFilter, if authentication is successful an Authentication request token will be placed into the - ContextHolder. If the authentication event was - successful, or authentication was not attempted because the HTTP + SecurityContextHolder. If the authentication event + was successful, or authentication was not attempted because the HTTP header did not contain a Digest Authentication request, the filter chain will continue as normal. The only time the filter chain will be interrupted is if authentication fails and the @@ -2777,10 +2701,11 @@ key: A private key to prevent modification of the nonce token logout and home pages of an application. There are also other situations where anonymous authentication would be desired, such as when an auditing interceptor queries the - ContextHolder to identify which principal was - responsible for a given operation. Such classes can be authored with - more robustness if they know the ContextHolder - always contains an Authentication object, and never + SecurityContextHolder to identify which principal + was responsible for a given operation. Such classes can be authored + with more robustness if they know the + SecurityContextHolder always contains an + Authentication object, and never null. Acegi Security provides three classes that together provide an @@ -2795,7 +2720,7 @@ key: A private key to prevent modification of the nonce token Finally, there is an AnonymousProcessingFilter, which is chained after the normal authentication mechanisms and automatically add an AnonymousAuthenticationToken to the - ContextHolder if there is no existing + SecurityContextHolder if there is no existing Authentication held there. The definition of the filter and authentication provider appears as follows: @@ -2886,7 +2811,7 @@ public void loginSuccess(HttpServletRequest request, HttpServletResponse respons loginFail() and loginSuccess() methods. The autoLogin() method is called by RememberMeProcessingFilter whenever the - ContextHolder does not contain an + SecurityContextHolder does not contain an Authentication. This interface therefore provides the underlaying remember-me implementation with sufficient notification of authentication-related events, and delegates to the @@ -2967,19 +2892,20 @@ key: A private key to prevent modification of the remember-me token locations" in discussions about storing the Authentication. This approach did not explicitly separate the function of HttpSession storage of - ContextHolder contents from the processing of - authentication requests received through various protocols. In + SecurityContextHolder contents from the processing + of authentication requests received through various protocols. In addition, the previous approach did not facilitate storage of non-Authentication objects between requests, which - was limiting usefulness of the ContextHolder system - to member of the community. For these reasons, the notion of - well-known locations was abandoned, the - HttpSessionContextIntegrationFilter was - established, and the purpose of authentication processing mechanisms - was explicitly defined and limited to interaction with the - ContextHolder only. There is no need to refer to - well-known locations any more and we hope this clearer separation of - responsibilities enhances understanding of the project. + was limiting usefulness of the + SecurityContextHolder system to member of the + community. For these reasons, the notion of well-known locations was + abandoned, the HttpSessionContextIntegrationFilter + was established, and the purpose of authentication processing + mechanisms was explicitly defined and limited to interaction with the + SecurityContextHolder only. There is no need to + refer to well-known locations any more and we hope this clearer + separation of responsibilities enhances understanding of the + design. @@ -3063,10 +2989,10 @@ key: A private key to prevent modification of the remember-me token 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 + SecurityContext in the + SecurityContextHolder 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 @@ -3672,7 +3598,7 @@ $CATALINA_HOME/bin/startup.sh authentication approach. Usually the HttpSessionIntegrationFilter will be used to associate the Authentication object with the - ContextHolder for the duration of each + SecurityContextHolder for the duration of each request. @@ -4108,7 +4034,7 @@ $CATALINA_HOME/bin/startup.sh Configuring the X509 Provider There is a version of the contacts sample application which + linkend="security-sample">Contacts Sample Application which uses X509. Copy the beans and filter setup from this as a starting point for configuring your own application. A set of example certificates is also included which you can use to configure your @@ -4273,14 +4199,15 @@ $CATALINA_HOME/bin/startup.sh context. Note that the redirections are absolute (eg - http://www.company.com:8080/app/page), not relative (eg /app/page). - During testing it was discovered that Internet Explorer 6 Service Pack - 1 has a bug whereby it does not respond correctly to a redirection - instruction which also changes the port to use. Accordingly, absolute - URLs are used in conjunction with bug detection logic in the - PortResolverImpl that is wired up by default to - many Acegi Security beans. Please refer to the JavaDocs for - PortResolverImpl for further details. + http://www.company.com:8080/app/page), not relative + (eg /app/page). During testing it was discovered + that Internet Explorer 6 Service Pack 1 has a bug whereby it does not + respond correctly to a redirection instruction which also changes the + port to use. Accordingly, absolute URLs are used in conjunction with + bug detection logic in the PortResolverImpl that is + wired up by default to many Acegi Security beans. Please refer to the + JavaDocs for PortResolverImpl for further + details. @@ -4349,9 +4276,9 @@ $CATALINA_HOME/bin/startup.sh could consult a collection within the Customer domain object instance to determine which users have access. By using the - ContextHolder.getContext() and casting it to - SecureContext, you'll be able to access the - Authentication object. + SecurityContextHolder.getContext().getAuthentication(), + you'll be able to access the Authentication + object. @@ -4816,6 +4743,10 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); FilterChainProxy + We strongly recommend to use FilterChainProxy + instead of adding multiple filters to + web.xml. + Whilst FilterToBeanProxy is a very useful class, the problem is that the lines of code required for <filter> and @@ -4911,10 +4842,18 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); need to redirect to a different protocol + + ConcurrentSessionFilter, because it + doesn't use any SecurityContextHolder + functionality but needs to update the + SessionRegistry to reflect ongoing requests + from the principal + + HttpSessionContextIntegrationFilter, so a Context can be setup in the - ContextHolder at the beginning of a web + SecurityContextHolder at the beginning of a web request, and any changes to the Context can be copied to the HttpSession when the web request ends (ready for use with the next web request) @@ -4926,8 +4865,9 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); CasProcessingFilter, BasicProcessingFilter, HttpRequestIntegrationFilter, JbossIntegrationFilter etc - so that the - ContextHolder can be modified to contain a - valid Authentication request token + SecurityContextHolder can be modified to + contain a valid Authentication request + token @@ -4940,16 +4880,17 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); RememberMeProcessingFilter, so that if no earlier authentication processing mechanism updated the - ContextHolder, and the request presents a - cookie that enables remember-me services to take place, a suitable - remembered Authentication - object will be put there + SecurityContextHolder, and the request presents + a cookie that enables remember-me services to take place, a + suitable remembered + Authentication object will + be put there AnonymousProcessingFilter, so that if no earlier authentication processing mechanism updated the - ContextHolder, an anonymous + SecurityContextHolder, an anonymous Authentication object will be put there @@ -4972,8 +4913,8 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); If you're using SiteMesh, ensure the Acegi Security filters execute before the SiteMesh filters are called. This enables the - ContextHolder to be populated in time for use by - SiteMesh decorators. + SecurityContextHolder to be populated in time for + use by SiteMesh decorators. @@ -5016,7 +4957,7 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); contain a success message similar to the following:
- Context on ContextHolder is of type: + Context on SecurityContextHolder is of type: net.sf.acegisecurity.context.secure.SecureContextImpl The Context implements SecureContext. @@ -5090,7 +5031,10 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); 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. + simply making suggestions. Please read our project policies web page + that is available on the Acegi Security home page. This explains the + path to become a committer, and the administration approaches we use + with the project. SourceForge provides CVS services for the project, allowing anybody to access the latest code. If you wish to contribute new code, @@ -5123,6 +5067,10 @@ INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); Use CamelCase + + Add code contributions to JIRA + + 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