9. Core Security Filters

There are some key filters which will always be used in a web application which uses Spring Security, so we'll look at these and their supporting classes and interfaces first. We won't cover every feature, so be sure to look at the Javadoc for them if you want to get the complete picture.

9.1 FilterSecurityInterceptor

We've already seen FilterSecurityInterceptor briefly when discussing access-control in general, and we've already used it with the namespace where the <intercept-url> elements are combined to configure it internally. Now we'll see how to explicitly configure it for use with a FilterChainProxy, along with its companion filter ExceptionTranslationFilter. A typical configuration example is shown below:

<bean id="filterSecurityInterceptor"
      class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="accessDecisionManager" ref="accessDecisionManager"/>
  <property name="securityMetadataSource">
    <security:filter-security-metadata-source>
      <security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
      <security:intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
    </security:filter-security-metadata-source>
  </property>
</bean>

FilterSecurityInterceptor is responsible for handling the security of HTTP resources. It requires a reference to an AuthenticationManager and an AccessDecisionManager. It is also supplied with configuration attributes that apply to different HTTP URL requests. Refer back to the original discussion on these in the technical introduction.

The FilterSecurityInterceptor can be configured with configuration attributes in two ways. The first, which is shown above, is using the <filter-security-metadata-source> namespace element. This is similar to the <http> element from the namespace chapter but the <intercept-url> child elements only use the pattern and access attributes. Commas are used to delimit the different configuration attributes that apply to each HTTP URL. The second option is to write your own SecurityMetadataSource, but this is beyond the scope of this document. Irrespective of the approach used, the SecurityMetadataSource is responsible for returning a List<ConfigAttribute> containing all of the configuration attributes associated with a single secure HTTP URL.

It should be noted that the FilterSecurityInterceptor.setSecurityMetadataSource() method actually expects an instance of FilterInvocationSecurityMetadataSource. This is a marker interface which subclasses SecurityMetadataSource. It simply denotes the SecurityMetadataSource understands FilterInvocations. In the interests of simplicity we'll continue to refer to the FilterInvocationSecurityMetadataSource as a SecurityMetadataSource, as the distinction is of little relevance to most users.

The SecurityMetadataSource created by the namespace syntax obtains the configuration attributes for a particular FilterInvocation by matching the request URL against the configured pattern attributes. This behaves in the same way as it does for namespace configuration. The default is to treat all expressions as Apache Ant paths and regular expressions are also supported for more complex cases. The path-type attribute is used to specify the type of pattern being used. It is not possible to mix expression syntaxes within the same definition. As an example, the previous configuration using regular expressions instead of Ant paths would be written as follows:

<bean id="filterInvocationInterceptor"
      class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="accessDecisionManager" ref="accessDecisionManager"/>
  <property name="runAsManager" ref="runAsManager"/>
  <property name="securityMetadataSource">
    <security:filter-security-metadata-source path-type="regex">
      <security:intercept-url pattern="\A/secure/super/.*\Z" access="ROLE_WE_DONT_HAVE"/>
      <security:intercept-url pattern="\A/secure/.*\" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
    </security:filter-security-metadata-source>
  </property>
</bean>        

Patterns are always evaluated in the order they are defined. Thus it is important that more specific patterns are defined higher in the list than less specific patterns. This is reflected in our example above, where the more specific /secure/super/ pattern appears higher than the less specific /secure/ pattern. If they were reversed, the /secure/ pattern would always match and the /secure/super/ pattern would never be evaluated.

9.2  ExceptionTranslationFilter

The ExceptionTranslationFilter sits above the FilterSecurityInterceptor in the security filter stack. It doesn't do any actual security enforcement itself, but handles exceptions thrown by the security interceptors and provides suitable and HTTP responses.

<bean id="exceptionTranslationFilter"
  class="org.springframework.security.web.access.ExceptionTranslationFilter">
 <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
 <property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</bean>

<bean id="authenticationEntryPoint"
  class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
 <property name="loginFormUrl" value="/login.jsp"/>
</bean>

<bean id="accessDeniedHandler"
     class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
  <property name="errorPage" value="/accessDenied.htm"/>
</bean>

9.2.1 AuthenticationEntryPoint

The AuthenticationEntryPoint will be called if the user requests a secure HTTP resource but they are not authenticated. An appropriate AuthenticationException or AccessDeniedException will be thrown by a security interceptor further down the call stack, triggering the commence method on the entry point. This does the job of presenting the appropriate response to the user so that authentication can begin. The one we've used here is LoginUrlAuthenticationEntryPoint, which redirects the request to a different URL (typically a login page). The actual implementation used will depend on the authentication mechanism you want to be used in your application.

9.2.2 AccessDeniedHandler

What happens if a user is already authenticated and they try to access a protected resource? In normal usage, this shouldn't happen because the application workflow should be restricted to operations to which a user has access. For example, an HTML link to an administration page might be hidden from users who do not have an admin role. You can't rely on hiding links for security though, as there's always a possibility that a user will just enter the URL directly in an attempt to bypass the restrictions. Or they might modify a RESTful URL to change some of the argument values. Your application must be protected against these scenarios or it will definitely be insecure. You will typically use simple web layer security to apply constraints to basic URLs and use more specific method-based security on your service layer interfaces to really nail down what is permissible.

If an AccessDeniedException is thrown and a user has already been authenticated, then this means that an operation has been attempted for which they don't have enough permissions. In this case, ExceptionTranslationFilter will invoke a second strategy, the AccessDeniedHandler. By default, an AccessDeniedHandlerImpl is used, which just sends a 403 (Forbidden) response to the client. Alternatively you can configure an instance explicitly (as in the above example) and set an error page URL which it will forwards the request to [14]. This can be a simple access denied page, such as a JSP, or it could be a more complex handler such as an MVC controller. And of course, you can implement the interface yourself and use your own implementation.

It's also possible to supply a custom AccessDeniedHandler when you're using the namespace to configure your application. See the namespace appendix for more details.

9.2.3 SavedRequests and the RequestCache Interface

Another of ExceptionTranslationFilter's responsibilities is to save the current request before invoking the AuthenticationEntryPoint. This allows the request to be restored after the use has authenticated (see previous overview of web authentication). A typical example would be where the user logs in with a form, and is then redirected to the original URL by the default SavedRequestAwareAuthenticationSuccessHandler (see below).

The RequestCache encapsulates the functionality required for storing and retrieving HttpServletRequest instances. By default the HttpSessionRequestCache is used, which stores the request in the HttpSession. The RequestCacheFilter has the job of actually restoring the saved request from the cache when the user is redirected to the original URL.

Under normal circumstances, you shouldn't need to modify any of this functionality, but the saved-request handling is a best-effort approach and there may be situations which the default configuration isn't able to handle. The use of these interfaces makes it fully pluggable from Spring Security 3.0 onwards.

9.3 SecurityContextPersistenceFilter

We covered the purpose of this all-important filter in the Technical Overview chapter so you might want to re-read that section at this point. Let's first take a look at how you would configure it for use with a FilterChainProxy. A basic configuration only requires the bean itself

<bean id="securityContextPersistenceFilter"
  class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>

As we saw previously, this filter has two main tasks. It is responsible for storage of the SecurityContext contents between HTTP requests and for clearing the SecurityContextHolder when a request is completed. Clearing the ThreadLocal in which the context is stored is essential, as it might otherwise be possible for a thread to be replaced into the servlet container's thread pool, with the security context for a particular user still attached. This thread might then be used at a later stage, performing operations with the wrong credentials.

9.3.1 SecurityContextRepository

From Spring Security 3.0, the job of loading and storing the security context is now delegated to a separate strategy interface:

public interface SecurityContextRepository {
  SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);
  void saveContext(SecurityContext context, HttpServletRequest request,
         HttpServletResponse response);
}

The HttpRequestResponseHolder is simply a container for the incoming request and response objects, allowing the implementation to replace these with wrapper classes. The returned contents will be passed to the filter chain.

The default implementation is HttpSessionSecurityContextRepository, which stores the security context as an HttpSession attribute [15]. The most important configuration parameter for this implementation is the allowSessionCreation property, which defaults to true, thus allowing the class to create a session if it needs one to store the security context for an authenticated user (it won't create one unless authentication has taken place and the contents of the security context have changed). If you don't want a session to be created, then you can set this property to false:

<bean id="securityContextPersistenceFilter"
    class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
  <property name='securityContextRepository'>
    <bean class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
      <property name='allowSessionCreation' value='false' />
    </bean>
  </property>
</bean>

Alternatively you could provide an instance of NullSecurityContextRepository, a null object implementation, which will prevent the security context from being stored, even if a session has already been created during the request.

9.4 UsernamePasswordAuthenticationFilter

We've now seen the three main filters which are always present in a Spring Security web configuration. These are also the three which are automatically created by the namespace <http> element and cannot be substituted with alternatives. The only thing that's missing now is an actual authentication mechanism, something that will allow a user to authenticate. This filter is the most commonly used authentication filter and the one that is most often customized [16]. It also provides the implementation used by the <form-login> element from the namespace. There are three stages required to configure it.

  1. Configure a LoginUrlAuthenticationEntryPoint with the URL of the login page, just as we did above, and set it on the ExceptionTranslationFilter.

  2. Implement the login page (using a JSP or MVC controller).

  3. Configure an instance of UsernamePasswordAuthenticationFilter in the application context

  4. Add the filter bean to your filter chain proxy (making sure you pay attention to the order).

The login form simply contains j_username and j_password input fields, and posts to the URL that is monitored by the filter (by default this is /j_spring_security_check). The basic filter configuration looks something like this:

<bean id="authenticationFilter" class=
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="filterProcessesUrl" value="/j_spring_security_check"/>
</bean> 
                

9.4.1 Application Flow on Authentication Success and Failure

The filter calls the configured AuthenticationManager to process each authentication request. The destination following a successful authentication or an authentication failure is controlled by the AuthenticationSuccessHandler and AuthenticationFailureHandler strategy interfaces, respectively. The filter has properties which allow you to set these so you can customize the behaviour completely [17]. Some standard implementations are supplied such as SimpleUrlAuthenticationSuccessHandler, SavedRequestAwareAuthenticationSuccessHandler, SimpleUrlAuthenticationFailureHandler and ExceptionMappingAuthenticationFailureHandler. Have a look at the Javadoc for these classes and also for AbstractAuthenticationProcessingFilter to get an overview of how they work and the supported features.

If authentication is successful, the resulting Authentication object will be placed into the SecurityContextHolder. The configured AuthenticationSuccessHandler will then be called to either redirect or forward the user to the appropriate destination. By default a SavedRequestAwareAuthenticationSuccessHandler is used, which means that the user will be redirected to the original destination they requested before they were asked to login.

[Note]Note

The ExceptionTranslationFilter caches the original request a user makes. When the user authenticates, the request handler makes use of this cached request to obtain the original URL and redirect to it. The original request is then rebuilt and used as an alternative.

If authentication fails, the configured AuthenticationFailureHandler will be invoked.



[14] We use a forward so that the SecurityContextHolder still contains details of the principal, which may be useful for displaying to the user. In old releases of Spring Security we relied upon the servlet container to handle a 403 error message, which lacked this useful contextual information.

[15] In Spring Security 2.0 and earlier, this filter was called HttpSessionContextIntegrationFilter and performed all the work of storing the context was performed by the filter itself. If you were familiar with this class, then most of the configuration options which were available can now be found on HttpSessionSecurityContextRepository.

[16] For historical reasons, prior to Spring Security 3.0, this filter was called AuthenticationProcessingFilter and the entry point was called AuthenticationProcessingFilterEntryPoint. Since the framework now supports many different forms of authentication, they have both been given more specific names in 3.0.

[17] In versions prior to 3.0, the application flow at this point had evolved to a stage was controlled by a mix of properties on this class and strategy plugins. The decision was made for 3.0 to refactor the code to make these two strategies entirely responsible.