Spring Security 3 offers a number of improvements over Spring Security 2, such as the addition of Spring EL expressions in access declarations and better support for session management. Spring Security 3 also introduces a number of changes such as the removal of the NtmlFilter.

In most cases, a migration from Spring Security 2 to Spring Security 3 is rather straightforward, but when custom spring security filters are present, additional work needs to be done.

In this article we discuss all changes required to do the migration. We also recommend the order in which the changes are discussed as the order in which to do them.

1. Importing the dependencies

One of the biggest overall changes between Spring Security 2 and Spring Security 3 is that Spring Security 3 takes a more modular approach. Spring Security 3 was divided into modules. The modules you will encounter in pretty much any webapp that is secured with spring-security are:

  1. spring-security-core(core classes such as Authentication, Voter, and the like)
  2. spring-security-web(all core classes that are dependent on servlet api, such as all spring security filters)
  3. spring-security-config(needed to use the spring security xml namespace in spring applicationContext files)

There are lot of other specific modules, such as spring-security-ldap and spring-security-asm.

A maven dependency such as

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>

would change to the following dependencies:

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>

2. Changing the classnames

One of the effects of the modularisation is that a lot of spring security framework classes were moved to a more specific package.

SecurityContextHolder’s package changed from org.springframework.security.context to org.springframework.security.core.context for example.

In order to do a successful migration, it is necessary to change the import declaration of all spring security classes in classes that make use of them.

3. Handling small changes to the API

Usually, just changing the imported spring security class’s package name is enough. However, the api of some spring security framework classes was changed as well. Usually, these changes are rather small and easy to deal with.

Some of these small changes that come to mind:

  • SpringSecurityException does not exist any longer. The quickest migration is to let it extend from RuntimeException or NestedRuntimeException instead of SpringSecurityException. Note that the specific Spring Security exceptions, such as AccessDeniedException and AuthenticationException still exist, but just extend RuntimeException directly now.
  • The decide method of AccessDecisionVoter now takes a collection of ConfigAttribute instead of a ConfigAttributeDefinition. ConfigAttributeDefinition was basically just a decorator for a collection of ConfigAttribute elements.
  • SavedRequest is now an interface instead of a concrete class. In order to instantiate a default implementation, instantiate DefaultSavedRequest.
  • The default User of the UserDetails interface does not have a setAuthorities method anymore. The authorities are passed to the constructor, in the implementation the variable is final.

4. Rewriting the filters

Usually, a migration from Spring Security 2 to Spring Security 3 is straightforward. However, if you implemented custom spring security filters, chances are you will have a bit more work. The basic filter class from the Spring Security specific SpringSecurityFilter changed to the generic Spring web GenericFilterBean and the API of this class changed a lot more than the API of other classes.

Especially AbstractProcessingFilter(now AbstractAuthenticationProcessingFilter) changed. In Spring Security 3.0, the determineFailureUrl and determineTargetUrl methods were removed in favour of adding separate Handler instances(AuthenticationSuccessHandler, AuthenticationFailureHandler,..) to these classes, which makes the filters more configurable/reusable. A similar story for LogoutFilter(determineRedirectUrl removed in favour of adding a LogoutSuccessHandler).

5. Changing the security related applicationContext files

Last but not least, the spring applicationContext in which all the spring security beans are defined needs to change to.

At the very least, the spring security namespace schema will need to be changed from http://www.springframework.org/schema/security/spring-security-2.0.xsd to http://www.springframework.org/schema/security/spring-security-3.0.xsd. Forgetting to do this whill result in a BeanDefinitionParsingException upon application deploy.

The spring security xml namespace underwent quite some changes too.
One of the most notable changes is the removal of custom-authentication-provider and custom-filter inside authenticationProvider and custom spring security filter beans. Authentication providers are now injected explicitly or configured as <security:authentication-provider ref=””> within the authenticationManager bean. Custom filters can be declared explicitly in the spring security filter chain bean declaration, or they can be included with <custom-filter> within the <http> element in case this one is used.
Another notable change within the spring security xml namespace is that authentication-provider is now declared as a child of authentication-manager.

It is also necessary to change the classnames of the spring security framework classes that changed package in the applicationContext file(s).

And finally, some beans expect other properties than they used to. These injections need to be corrected too. For example, FilterSecurityInterceptor does not take a String anymore but needs to be injected with or a proper securityMetadataSource or needs to be declared with a fully configured security:filter-security-metadata-source tag.