11. Session Management

HTTP session related functonality is handled by a combination of the SessionManagementFilter and the SessionAuthenticationStrategy interface, which the filter delegates to. Typical usage includes session-fixation protection attack prevention, detection of session timeouts and restrictions on how many sessions an authenticated user may have open concurrently.

11.1 SessionManagementFilter

The SessionManagementFilter checks the contents of the SecurityContextRepository against the current contents of the SecurityContextHolder to deterine whether a user has been authenticated during the current request, typically by a non-interactive authentication mechanism, such as pre-authentication or remember-me [10]. If the repository contains a security context, the filter does nothing. If it doesn't, and the thread-local SecurityContext contains a (non-anonymous) Authentication object, the filter assumes they have been authenticated by a previous filter in the stack. It will then invoke the configured SessionAuthenticationStrategy.

If the user is not currently authenticated, the filter will check whether an invalid session ID has been requested (because of a timeout, for example) and will redirect to the configured invalidSessionUrl if set. The easiest way to configure this is through the namespace, as described earlier.

11.2 SessionAuthenticationStrategy

SessionAuthenticationStrategy is used by both SessionManagementFilter and AbstractAuthenticationProcessingFilter, so if you are using a customized form-login class, for example, you will need to inject it into both of these. In this case, a typical configuration, combining the namespace and custom beans might look like this:

  <http>  
    <custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />     
    <session-management session-authentication-strategy-ref="sas"/>      
  </http>
  
  <beans:bean id="myAuthFilter" 
      class="org.springframework.security.web.authentcation.UsernamePasswordAuthenticationFilter">
    <beans:property name="sessionAuthenticationStrategy" ref="sas" />
    ...
  </beans:bean>
  
  <beans:bean id="sas" 
      class="org.springframework.security.web.session.DefaultAuthenticatedSessionStrategy">
    <beans:property name="sessionRegistry" ref="sessionRegistry" />
    <beans:property name="maximumSessions" value="1" />
  </beans:bean>
       
      

11.3 Concurrency Control

Spring Security is able to prevent a principal from concurrently authenticating to the same application more than a specified number of times. Many ISVs take advantage of this to enforce licensing, whilst network administrators like this feature because it helps prevent people from sharing login names. You can, for example, stop user "Batman" from logging onto the web application from two different sessions.

This feature is supported by the namespace, so please check the earlier namespace chapter for the simplest configuration. Sometimes you need to customize things though.

The implementation uses a specialized version of SessionAuthenticationStrategy, called ConcurrentSessionControlStrategy.

[Note]Note

Previously the concurrent authentication check was made by the ProviderManager, which could be injected with a ConcurrentSessionController. The latter would check if the user was attempting to exceed the number of permitted sessions. However, this approach required that an HTTP session be created in advance, which is undesirable. In Spring Security 3, the user is first authenticated by the AuthenticationManager and once they are successfully authenticated, a session is created and the check is made whether they are allowed to have another session open.

To use concurrent session support, you'll need to add the following to web.xml:

  <listener>
    <listener-class>
      org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
  </listener>        
        

In addition, you will need to add the ConcurrentSessionFilter to your FilterChainProxy. The ConcurrentSessionFilter requires two properties, sessionRegistry, which generally points to an instance of SessionRegistryImpl, and expiredUrl, which points to the page to display when a session has expired. A configuration using the namespace to create the FilterChainProxy and other default beans might look like this:

  <http>
    <custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />  
    <custom-filter position="AUTHENTICATION_PROCESSING_FILTER" ref="myAuthFilter" />     
        
    <session-management session-authentication-strategy-ref="sas"/>      
  </http>
  
  <beans:bean id="concurrencyFilter" 
      class="org.springframework.security.web.session.ConcurrentSessionFilter">
    <beans:property name="sessionRegistry" ref="sessionRegistry" />
    <beans:property name="expiredUrl" value="/session-expired.htm" />
  </beans:bean>
  
  <beans:bean id="myAuthFilter" 
      class="org.springframework.security.web.authentcation.UsernamePasswordAuthenticationFilter">
    <beans:property name="sessionAuthenticationStrategy" ref="sas" />
    ...
  </beans:bean>
  
  <beans:bean id="sas" 
      class="org.springframework.security.web.session.ConcurrentSessionControlStrategy">
    <beans:property name="sessionRegistry" ref="sessionRegistry" />
    <beans:property name="maximumSessions" value="1" />
  </beans:bean>
  
  <beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
       
    

Adding the listener to web.xml 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. Without it, a user will never be able to log back in again once they have exceeded their session allowance, even if they log out of another session or it times out.



[10] Authentication by mechanisms which perform a redirect after authenticating (such as form-login) will not be detected by SessionManagementFilter, as the filter will not be invoked during the authenticating request. Session-management functionality has to be handled separately in these cases.