Spring Security is a comprehensive framework for implementing security solutions in JavaEE applications which provides substantially more functionality than simple JavaEE Container Managed Security and is becoming popular within the java development community. It is important that we understand how OpenAM can be used with Spring Security and describe the integration options available to applications utilising it.
What the Spring Security OpenAM Extension Offers
- Authentication & Single Sign On via OpenAM
- Use of OpenAM Login Page Spring Security authorisation tag libraries
- Spring Security Method level authorisation (annotations)
- OpenAM URL pattern based authorisations
+ Behaviour very similar to Agent (e.g. triggers Auth by default).
– OpenAM authentication is triggered regardless of the presence of policy (Spring or OpenAM) on a URL. Unauthenticated pages need to be explicitly excluded from Authentication.
– It does not appear to be possible to map OpenAM group names to Spring role names (i.e. the OpenAM group needs to be used as the role name)
– Application login pages cannot be used (i.e. the OpenAM login page must be used).
– The applicationContext needs information about the OpenAM setup (duplicated from the AMConfig.properties)
– Logging is configured independently of the Spring logging configuration. – Configuration needs to be expanded (doesn't work with namespaces).
– Requires server side cookie encoding (which we have turned off in our deployment).
An example project is available in the following subversion repository:
This is a Maven project which produces a web application which uses the spring security provider.
The application has several web pages which show how the spring security provider integrates with OpenAM. The features are:
- Single sign-on: we will see two web applications in the same browser with the OpenAM configuration needed to provide unique authentication. If the user logs out from one, then the other applications' session expires too.
- Authorization management: Defined in the OpenAM manager application for every application which is in the security realm.
The main file is src/main/webapp/WEB-INF/web.xml where the JEE configuration is defined. The components are:
- Java Server Faces
- Spring Framework
- Spring Security
The main configuration is defined in the following Spring config file:
This file contains an import which has the security configuration. (In a more complex application, this would also contain configuration for persistence, web service, etc. See details in the Spring docs). ac-security.xml is the most important file of the example, see below.
The file src/main/webapp/WEB-INF/faces-config.xml has the Java Server Faces configuration. In this example it is almost empty. It contains only the integration with Spring.
The file src/main/resources/AMConfig.properties contains the OpenAM configuration. The admin user credentials are specified in these properties:
You will need to configure AMConfig.properties according to your settings.
If you don't already have OpenAM installed, you can download it from here:
This file is the most important of the example. It shows how the application should be configured using Spring Security with the implementation of the OpenAM provider.
In Spring Security 2.0+ the configuration is simpler than in Acegi for Spring Framework (see documentation: http://static.springsource.org/spring-security/site/index.html) for an application with default configuration. But, with the OpenAM provider we have to use the old Acegi style configuratoin.
This file has the following beans:
- filterChainProxy: This is the main bean. It defines every security filter which goes to receive the request. The order of each filter is very important. In XML comments, the order of the used filters and the order of all possible filters defined in Spring Security framework, are given.
- httpSessionContextIntegrationFilter: This is responsible for storing the security context between HTTP requests.
- logoutFilter: Performs the logout from the application and in every application where the user is logged in via single sign-on.
- openssoFilter: Responsible for processing authentications.
- exceptionTranslationFilter: Manages the requests which are rejected by the other filters or that do not have a authenticated session or have denied access
- filterInvocationInterceptor: The last filter. It manages the authentication and authorization of each request.
- authenticationManager: Authentication manager used by filterInvocationInterceptor.
- authenticationEntryPoint: Defines the login page and the authentication URL
- accessDecisionManager: Authorization manager used by filterInvocationInterceptor
The class com.sun.identity.shared.encode.CookieUtils is the unique code of the project. For this example, it is not necessary however this class is needed because it belongs to the OpenAM client SDK. It is a patch to get working in any servlet container without the OpenSSO agent.
Building & deploy
Simply run the following (assuming you have Maven installed):
$ mvn package
Deploy the war file in Tomcat (or whichever web container you are using)
If you want to execute the application in a servlet container without an OpenAM agent, you must define the system properties "com.iplanet.am.cookie.name" and "com.sun.identity.federation.fedCookieName".
For example in Tomcat, you must write in a command shell:
$ export CATALINA_OPTS=-Dcom.iplanet.am.cookie.name=iPlanetDirectoryPro -Dcom.sun.identity.federation.fedCookieName=fedCookie $CATALINA_OPTS
or in windows:
> set CATALINA_OPTS=-Dcom.iplanet.am.cookie.name=iPlanetDirectoryPro -Dcom.sun.identity.federation.fedCookieName=fedCookie %CATALINA_OPTS%
Testing single sign-on is very simple. Open two tabs in the same browser. In the first tab open the example application, in the second tab open another OpenAM application, for example, OpenAM manager. And execute the following scenarios:
- Login to the example application with a LDAP user
- Reload OpenAM application page and see you are already login
- Logout of example application
- Reload OpenAM application page and see you are already logout
- Login in to OpenAM with a LDAP user
- Reload example application page and see you are already login
- Logout of OpenAM
- Reload example application page and see you are already logout
To test authorization through OpenAM configuration we must define the realm policies in the OpenAM manager. But first we need a user group to assign to. Go to Access Control -> Realm -> Subjects -> Group ->
"New ...", then give a name, for example, "Staff". And in the "User" tab, we add several users.
In OpenAM, create two groups "staff" and "admins"
Add a sample user to each group (e.g. put demo1 in the admins group, demo2 is in staff)
Create a URL policy by selecting Policies -> "New Policy" and assign it a name, for example, "Protected Info".
In the Rules section we create one "URL Policy Agent" with the following data:
Name: Protected Info
Resource Name: http://*:*/faces/protected*
Subject: Admins ** Exclusive **
Make sure to check the "exclusive" box in the Subject selection. This will apply
this policy to everyone EXCEPT Admins
Create another blanket policy to allow access to the application:
Resource Name: http://*:*/faces/*
Subject: All authenicated users
Experiment with the application by logging on with your demo accounts.
- The user is redirected to OpenAM for authentication
- There are sample staff pages that print a different message if you are staff vs. an admin
- Only an admin user should have access to the protected/ section
We can see the configuration for single sign-on is very simple and we've also got a centralized security policy definition.
The integration of OpenSSO with Spring Security gives additional features. For example, Spring AOP is useful for associating policies to business objects without writing it in the code. The security configuration of the business objects are independent of the application which are using it, which is very useful for distributed applications within a security realm.
This provider can also be used in other JavaEE modules as an EJB which is accessed by RMI.
Configuration Best Practice
As the Spring Context File & AMConfig.properties require references to the various login urls, there are a few steps that can be taken to ensure that your app is portable and not tied to any specific environment:
1. Load the OpenAM login URL from a properties file.
While the OpenAM provider requires you to specify the login URL within the
OpenSSOProcessingFilterEntryPoint, Spring's PropertyPlaceholderConfigurer makes it easy to grab this from a properties file. As luck would have it, the login URL is already available in the AMConfig.properties, so it is relatively straightforward to load this property from there by modifying the Spring Context as follows:
2. Externalise AMConfig.properties from the application.
Given that all of the environment specific OpenAM configuration is now contained within the AMConfig.properties file, this can now be externalised. The easiest way to achieve this is to ensure a local directory (e.g. /config) is placed on the classpath, and then the AMConfig.properties file deployed to this location. This file can then be managed independently of the packaged application.
3. Logging Configuration
Problably common sense, but ensure that the directory used in the com.iplanet.services.debug.directory file is the same place as the rest of the logging within your application, e.g.
Based on these findings, try to avoid widespread use of this module, and instead integrate Spring Security apps with the container (JAAS) and then use our standard agent approach. This would allow Spring Security apps to be developed against container managed security, and then integrate at the infrastructure layer, but with all the Spring Security benefits. This also removes the need for the app to carry around OpenAM configuration. More information on this approach is available by looking into the Spring Security Pre-Auth Filter