|PREV PACKAGE NEXT PACKAGE||FRAMES NO FRAMES|
|ApplicationSecurityManager||This interface defines the operations required of an Application Security Manager for the RCP framework.|
|AuthenticationAware||A Spring managed bean implementing this interface will be automatically notified of any change in the user's Authentication token.|
|LoginAware||A Spring managed bean implementing this interface will be automatically notified of any user login or logout activities.|
|SecurityController||A security controller is responsible for authorizing other
|SecurityControllerManager||A SecurityControllerManager is responsible for linking a controllable object, one that
|AuthenticationEvent||Event fired when the user's authentication token changes.|
|AuthenticationFailedEvent||Event fired when an authentication attempt fails.|
|ClientSecurityEvent||Parent for all RCP security related application events.|
|LoginCommand||Provides a login interface to the user.|
|LoginDetails||This class provides a bean suitable for use in a login form, providing properties for storing the user name and password.|
|LoginEvent||Event fired when a user logs in.|
|LoginForm||This class provides a simple form for capturing a username and password from the user.|
|LogoutCommand||Provides a command to log the current user out.|
|LogoutEvent||Event fired when a user logs out.|
|RemotingSecurityConfigurer||Correctly configures the username and password on Spring's remoting proxy factory beans.|
|SecurityAwareConfigurer||This class performs two main functions:
It is a bean post-processor that will set the current authentication token on any
newly created beans that implement
|SessionDetails||Deprecated. by the creation of new
Integrates Acegi Security System for Spring into RCP.
Acegi Security is a comprehensive open-source security system that delivers fully-featured security to Spring applications. To learn more about Acegi Security or access detailed documentation, please visit the project home page at http://acegisecurity.sourceforge.net.
It is envisaged that many RCP clients will be connecting with a remote Spring-powered server. In such deployments, security becomes of paramount importance. Whilst transport-layer security (such as HTTPS, port filtering and firewalls) are essential to almost all production applications, this package delivers comprehensive application-layer security to RCP clients by hooking into the Acegi Security project.
Whilst you should really read the Acegi Security System for Spring reference documentation to fully understand the architecture, the most important details you need to understand in order to utilize this RCP package is the summarized below.
RCP uses the following key Acegi Security classes and interfaces:
ContextHolder, which simply uses a ThreadLocal to store a SecureContext implementation.
Authentication, which stores the details of a principal, credentials and its granted authorities. RCP uses Acegi Securit's UsernamePasswordAuthenticationToken, which simply represents a username and password for the principal and credentials respectively.
AuthenticationManager, which is able to accept a request Authentication object (containing only the principal and credentials details), process its validity, and return a populated Authentication object (also containing the GrantedAuthortys).
One thing to keep in mind is that Acegi maintains authentication credentials on a per-thread basis (ContextHolder described above). This makes sense when considering server side implementations where different threads are working on behalf of potentially different principals. In a rich application, however, it is rare to have anything but a "global" notion of the logged in user (and associated credentials). In fact, having a per-thread credential store is problematic for a rich application where operations may take place on different threads (a main thread, UI event dispatch thread, worker threads, etc.). Further, it would be difficult to propogate credentials to all new threads created, or to update existing threads when a user changes credentials (such as loggin out or logging in as a different user).
For these reasons, the application security model provided within RCP uses a global store for credentials. See the ApplicationSecurityManager below.
Instances of ApplicationSecurityManager are responsible for performing the security operations of user login and logout and maintaining the global authentication token for the user. A default implementation is provided in DefaultApplicationSecurityManager.
An instance of the ApplicationSecurityManager is available from
ApplicationServices like this:
Application code can access the current authentication token by calling the
getAuthentication() method (or it can implement the notification
interfaces defined below).
As the ApplicationSecurityManager handles login/logout requests, it fires a set of events to inform the application of the security lifecycle. The table below shows the events that are fired in response to various login and logout processing.
|Successful login||AuthenticationEvent, LoginEvent|
In order to perform authentication operations, the ApplicationSecurityManager must have an AuthenticationManager configured. This can be done in the application context, like this:
<bean id="applicationSecurityManager" class="org.springframework.richclient.security.support.DefaultApplicationSecurityManager"> <property name="authenticationManager" ref="authenticationManager"/> </bean>
LoginCommand is a simple implementation of an
ActionCommand that shows a dialog for collecting a user name and
password and then handing them off to the ApplicationSecurityManager to
perform the actual login processing (see below for more details).
LoginCommand makes some very simple assumptions on the vaildation constraints
for the username and password fields, so you might need to subclass it and
provide your own implementation of the login form.
LoginCommand implements a simplistic login failure
handling scheme - it lets the user keep trying as long as they want. Again,
you'll probably want to subclass to provide something more clever. Future
work will hopefully include a pluggable login failure handling strategy. One
final configurable element on the LoginCommand is how the login dialog should
respond to the user pressing the Cancel button. This handling is controlled
closeOnCancel property on LoginCommand, which defaults to
closeOnCancel is true and the user cancels the dialog,
then the applicaiton will be closed, by calling
LogoutCommand is an implementation of ActionCommand
that simply invokes the logout processing in the ApplicationSecurityManager.
AuthenticationAware is a tag interface that marks
beans in the application context. Any bean that implements this interface
will be initially notified of the current authentication token (during bean
post-processing) and subsequently notified whenever the authentication token
changes. See SecurityAwareConfigurer for more details.
LoginAware is a tag interface that marks beans in
the application context. Any bean that implements this interface will be
notified of two major security events: login and logout.
See SecurityAwareConfigurer for more details.
SecurityAwareConfigurer is a key player in the security
architecture. It is both a BeanPostProcessor and an ApplicationListener. Its
job is to handle beans that implement AuthenticationAware and LoginAware and
configure them with authenticaiton information and notify them of key security
As a bean post-processor, SecurityAwareConfigurer handles any bean that implements AuthenticationAware and configures them with the current authentication token.
As an ApplicationListener, SecurityAwareConfigurer watches for ClientSecurityEvents and turns them into method notifications on the AuthenticationAware and LoginAware interfaces.
AuthenticationAware is handled in a "stateful" manner - meaning that the current authentication token is handed to every new bean that is created. Whereas the LoginAware interface is handled in an "event" manner - meaning that beans that implement the interface are only updated when an event of the proper type occurs.
AuthenticationAware notification always takes place prior to LoginAware notifications. So, if you need to perform some operation that requires another bean to have its authentiation state updated, then you should do it in LoginAware (or watch for LoginEvent and LogoutEvent instances directly) as these are always delivered after the AuthenticationAware notifications. See below in the remoting section for a real example of why this matters.
Each security event is translated to a notification, as shown below.
|AuthenticationFailedEvent||no notifications made|
Note that for any of this to happen, the SecurityAwareConfigurer must be properly configured in the application context. Here is an example of that configuration:
<bean id="securityAwareConfigurer" class="org.springframework.richclient.security.SecurityAwareConfigurer" lazy-init="false"/>
The ApplicationSecurityManager is responsible for firing events that correspond to important security lifecycle events (authentication, login, logout, etc.). Specific subtypes represent each important event:
|AuthenticationEvent||Event fired when the user's authentication changes. This happens on both a successful login and a logout.|
|AuthenticationFailedEvent||Event fired when an authentication attempt fails. This happens when a login is attempted and the authentication manager denies the authentication attempt.|
|LoginEvent||Event fired when a new user logs in. This happens when a user successfully logs in, and after the AuthenticationEvent.|
|LogoutEvent||Event fired when a user logs out. This happends when a user logs out, and after the AuthenticationEvent.|
Any bean interested in these events should implement ApplicationListener and then watch for events that extend ClientSecurityEvent. If you want a "callback" mechanism instead of watching events, then a bean can implement AuthenticationAware and/or LoginAware.
This package provides two key RCP commands: LoginCommand and LogoutCommand. To use these commands, simply add them to your commands-context.xml, like this:
<bean id="loginCommand" class="org.springframework.richclient.security.LoginCommand"/> <bean id="logoutCommand" class="org.springframework.richclient.security.LogoutCommand"/>
Both commands accept an optional property, displaySuccess, which defaults to true. This simply results in an information dialog being displayed after login or logout. You can switch this off by setting the property to false in the application context.
LoginCommand basically displays a dialog requesting the username and
password. Upon these being entered, a request Authentication
object is created (as mentioned in the Background Knowledge
section above) and presented for authentication by calling
ApplicationSecurityManager.doLogin. If the authentication
succeeds, a populated Authentication object is stored as the "global"
authentication toke (see above) and is returned to the caller
(the LoginCommand). The returned token is also placed into the thread-specific
ContextHolder (for a little bit of backward compatibility). As described above,
the ApplicationSecurityManager publishes events so other interested classes
know a login has taken place.
LogoutCommand is far simpler. It calls
ApplicationSecurityManager.doLogout, which fires appropriate events,
and then it updates the thread-specific ContextHolder so
its Authentication object is null.
As mentioned above, an AuthenticationManager is configured against
the LoginCommand. This is just like any other Acegi Security use of
AuthenticationManager, so you can use any of the standard Acegi Security
authentication providers with the RCP package (such as
More typically, a rich client will need to use a remote server for authentication.
In this case you need the client to ensure a username and password is valid
against the remote server, and also obtain the list of
GrantedAuthoritys (so the populated Authentication object can be
constructed). To achieve this, on the client you'll need to use the
RemoteAuthenticationProvider. On the server you'll need
to use the
RemoteAuthenticationManagerImpl. On the client
you'll use your preferred remoting proxy factory to access the server-side
RemoteAuthenticationManagerImpl. You can find these classes in Acegi
An example using the HTTP proxy would be configured like this:
<bean id="applicationSecurityManager" class="org.springframework.richclient.security.support.DefaultApplicationSecurityManager"> <property name="authenticationManager" ref="authenticationManager"/> </bean> <!-- Remote authentication manager configuration --> <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> <property name="providers"> <list> <ref bean="remoteAuthenticationProvider" /> </list> </property> </bean> <bean id="remoteAuthenticationProvider" class="org.acegisecurity.providers.rcp.RemoteAuthenticationProvider"> <property name="remoteAuthenticationManager" ref="remoteAuthenticationManager" /> </bean> <bean id="remoteAuthenticationManager" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean"> <property name="serviceUrl"> <value>http://localhost:8080/myserver/context/RemoteAuthenticationManager</value> </property> <property name="serviceInterface"> <value>org.acegisecurity.providers.rcp.RemoteAuthenticationManager</value> </property> </bean>
Using HTTP invocation for remoting is one of the simplest mechanisms to configure. Two classes are provided to make using HTTP BASIC authentication on top of the simple HTTP remoting protocol. See the code sample above on how one might configure the use of the HTTP proxy factory.
BasicAuthHttpInvokerProxyFactoryBean is an extension of
HttpInvokerProxyFactoryBean that supports the use of
BASIC authentication on each HTTP request. This factory takes care of instantiating
the proper invocation executor, an
and keeping it up to date with the latest user credentials.
AuthenticationAware in order to get notifications of changes in
the user's credentials. Please see the class documentation for
AuthenticationAware above to see how to properly configure the
application context so that authentication changes are broadcast properly.
If your application uses either the Hessian or Burlap remoting classes to
access your business objects on the server, you will want to register
RemotingSecurityConfigurer in your application context.
RemotingSecurityConfigurer listens for login and logout events and updates the usernames and passwords associated with any of your registered remoting proxy factories. This causes BASIC authentication to be used in the header of the remoting requests.
On the server side you will need to register Acegi Security's BasicProcessingFilter so BASIC authentication headers can be processed. You'd need to do this if you're using Acegi Security with any form of BASIC authentication (it is not an RCP-specific requirement). Here is an example of how you might configure this in the application context of your server:
<bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter"> <property name="authenticationManager"> <ref bean="authenticationManager" /> </property> <property name="authenticationEntryPoint"> <ref bean="basicProcessingFilterEntryPoint" /> </property> </bean> <bean id="basicProcessingFilterEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint"> <property name="realmName"> <value>My Realm</value> </property> </bean> <bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"> <property name="allowSessionCreation"> <value>false</value> </property> </bean> <!-- Allows remote clients to check if a username/password is valid --> <bean id="remoteAuthenticationManager" class="org.acegisecurity.providers.rcp.RemoteAuthenticationManagerImpl"> <property name="authenticationManager"> <ref bean="authenticationManager" /> </property> </bean> <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> <property name="providers"> <list> <ref bean="daoAuthenticationProvider" /> </list> </property> </bean> <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> <property name="authenticationDao"> <ref bean="authenticationDao" /> </property> </bean> <!-- Special implementation to get authentication data --> <bean id="authenticationDao" class="com.myco..security.MyAuthenticationDao"> </bean>
And in the web.xml you might install it like this:
<!-- Security configuration --> <filter> <filter-name>Acegi HTTP Session Integration</filter-name> <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> <init-param> <param-name>targetClass</param-name> <param-value>org.acegisecurity.context.HttpSessionContextIntegrationFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>Acegi HTTP Session Integration</filter-name> <url-pattern>/context/*</url-pattern> </filter-mapping> <filter> <filter-name>Acegi HTTP BASIC Authorization Filter</filter-name> <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> <init-param> <param-name>targetClass</param-name> <param-value>org.acegisecurity.ui.basicauth.BasicProcessingFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>Acegi HTTP BASIC Authorization Filter</filter-name> <url-pattern>/context/*</url-pattern> </filter-mapping>
Coming soon... The general idea will be CommandActions listen for events and update their visibility and enable/disabled status based on delegation to a security manager. The security manager will indicate the expected state based on granted authorities held.
|PREV PACKAGE NEXT PACKAGE||FRAMES NO FRAMES|