Spring Security Session – How to Control Session with Spring Security

In this article of Spring security tutorial, we will talk about the spring security session management. We will talk about the distinct features of Spring security which helps us in efficient and secure session management.

Spring Security Session

This article will talk through the spring security session management and how the spring security helps us to control the HTTP sessions.Spring security use the following options to control the HTTP session functionalities

  1. SessionManagementFilter.
  2. SessionAuthneticationStrategy

These 2 helps spring security to manage the following options in the security session:

  1. Session Timeout detection and handling.
  2. Concurrent sessions (how many sessions an authenticated user may have open concurrently).
  3. Session-fixation – handle the session

Let’s see the these options in details

1. When Is Session Created

Spring security provides different option to control the session creation. It provides us option to configure when the session will be created and how we can interact with the session. Here are the option available in the security which can help us configure and control the session creation.

  1. SessionCreationPolicy.ALWAYS – Session will always be created (if it does not exist).
  2. SessionCreationPolicy.NEVER – Spring Security will never create a HttpSession, but will use the HttpSession if it already exists (available through application server)
  3. SessionCreationPolicy.IF_REQUIRED – Spring Security will only create a HttpSession if required (default configuration. If you don’t specify, Spring security will use this option)
  4. SessionCreationPolicy.STATELESS – Spring Security will never create a HttpSession and it will never use it to get the SecurityContext.

For login based, application SessionCreationPolicy. IF_REQUIRED works for most cases and is also the default in Spring security.For a typical web application.To change the session creation policy in Spring security, we can override the configure method by overriding the WebSecurityConfigurerAdapter.

@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
    }
}

Let’s keep in mind following important points

  1. These configurations only control Spring security behavior but not your application. Your application might use different session creation configurations.
  2. By default, Spring security will create session when required. It can use the session created by your application outside of Spring security context. (remember sessions are created by application server).
  3. The STATELESS will ensure no session is created by Spring security, however that does not mean that your application will not create any session. This policy only applies to Spring security context. You might still see JSESIONID in your application, so don’t think that spring security configurations are not working.

Keep in mind that spring security handle the login and logout request with help of HTTP Session. The SessionCreationPolicy. STATELESS, Spring security will not use the cookies and every request needs re-authentication. I will cover it in a different post but one of the other option to use Spring session to manage your Spring session centrally.

1.1. Spring Security and HTTP Session

Spring security rely a lot on the HTTPSession and it’s very important that we clearly understand how spring security uses the HTTPSession method internally. Here is a high-level overview of the process.

  1. Spring security use the SecurityContext and SecurityContextHolder to store the authenticated object. Authenticated object has information about the logged-in users.
  2. The SecurityContextPersistenceFilter retrieves the SecurityContext for a request using the SecurityContextRepository (check source code for SecurityContextPersistenceFilter).Spring security by default use the HttpSessionSecurityContextRepository which use the HTTPRequest to get the HTTPSession.
  3. It will store the SecurityContext in the SecurityContextHolder.
  4. This SecurityContext is available throughout the request life-cycle.
  5. At the end of the request cycle, SecurityContextPersistenceFilter will clear the SecurityContextHolder (check finally block in the SecurityContextPersistenceFilter)

2. Spring Security Session Timeout

After the session timeout, we can redirect use to specific page if they submit a request with invalid session ID. To configure the redirect URL, we can use the configure method by overriding the WebSecurityConfigurerAdapter.

@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
            .invalidSessionUrl("/login");
    }
}

If you are working in the XML configuration, you can use session-manegement element to do this:

<http>
...
<session-management invalid-session-url="/login" />
</http>

When you deploy a Spring Boot app to a standalone server, configuring the session timeout is done in the same way as it would be in any other war deployment.

In the case of Tomcat we can set the session timeout by configuring the maxInactiveInterval attribute on the manager element in server.xml or using the session-timeout element in web.xml. Note that the first option will affect every app that’s deployed to the Tomcat instance.

 2.1.  Configure the Session Timeout with Spring Boot

Spring Boot comes with a lot of defaults and make it more easy to configure and customize the behavior using the application.properties file.To control the session timeout, use the following property

server.servlet.session.timeout= 120s

While using it, keep in mind the following important factors

  1. If you don’t specific the time unit (s in our case), spring boot will assume second as default unit.
  2. If you are on tomcat, it supports only minute precision e.g 187 will be treated as 3 minutes.

3. Spring Security Concurrent Session Control

There are certain applications (mainly financial applications) where we want to limit multiple logins for the same user. It’s also useful where you want to sell your service based on number of users and like to allow only specified users based on the license (Like cloud services which are sold number of user account basis). When users is authenticated and tried to re-authenticate them-self again, our application can respond in one of the following ways:

  1. Invalidate the existing session and create new authenticated session.
  2. Keep exiting session and throw/ show error message for the new login attempt.
  3. Allow both session to exists and let user to login from different place.

Spring security supports the feature to limit multiple login for the same user through session management. The first step to enable this feature it to add the HttpSessionEventPublisher listener in your application. Adding a listener in spring boot application is a bean configuration. The HttpSessionEventPublisher listener will keep spring security updated about the session life-cycle events.

/**
 * We need this bean for the session management. Specially if we want to control the concurrent session-control support
 * with Spring security.
 * @return
 */
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
    return new HttpSessionEventPublisher();
}

If you are using xml configurations, add the session-control support using the web.xml file:

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

3.1. Understanding Spring Security Concurrent Session Control

Spring Security concurrent session control is a powerful feature but make sure you understand it correctly before implementation. A wrong understanding can cause a lot of confusions and you might think that it is not working as expected. There are few important classes used internally by Spring security to enforce this feature. Here are some key components.

  1. SessionRegistry.
  2. ConcurrentSessionControlStrategy
  3. HttpSessionEventPublisher.
  4. SessionManagementFilter
  5. ConcurrentSessionFilter

Concurrent session control feature use the SessionRegistry to maintain a list of active HTTP session along with information of the associated authenticated users. It updates this SessionRegistry at a real time by Spring security every-time a session is created or destroy. We configured the HttpSessionEventPublisher earlier in this article, spring security use this event published to publish the events on the session life cycle and SessionRegistry is updated accordingly.

ConcurrentSessionControlStrategy is responsible to trek the new session and enforce the concurrent session policy. Every-time when a logged in customer try to access the secure part of application, the SessionManagementFilter will check the user active session in the SessionRegistry. The ConcurrentSessionFilter filter will recognize expired sessions and notify the user that their session has expired. To better understanding, You can also check the source code for these classes.Here is a high level workflow outlining how the spring security concurrent session control works:

Spring Security Concurrent Session Control

Let’s see the concurrent sessions feature in action.

3.2. Restricting the Number of Concurrent Sessions per User by Spring Security

With HttpSessionEventPublisher listener configuration, we can control the session multiple sessions feature for our application. Let’s take an example where we want to allow maximum 1 session per customer. If the maximum session exceeds 1, it will invalidate the first session by Spring security. how it can be done with spring security configuration:

@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
            .maximumSessions(1);
    }
}

You can download the application from our GitHub repository. Once the application started, execute the following steps to test it.

  1. Open the login page in Firefox and login with the valid username and password (make sure you created an account before this step.)
  2. Open chrome or any other browser (except Firefox) and login with the same username and password (used in step 1).
  3. Go back to the chrome browser and refresh or click on any link, you will see a similar message in your application
concurrent session control

This is the default message from spring security.Spring security provides the flexibility to configure an URL which will be called when user tried to do an additional login.To configure the expired session redirect, we can use the expiredUrl method.

@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
            .maximumSessions(1)
            .expiredUrl("/login?invalid-session=true");
    }
}

You can add some custom error message in your login page control.Rerun the application and follow above steps to test your application, in this case, you will see you custom error message and not the spring standard error message.

spring security session management

3.3. Disable Authentication

With default configurations (as explained in section 3.1 and 3.2), the second login will  cause the first login to be invalidated. This can sometime cause confusion. Imagine you are working and suddenly to see this message as your accidentally performed login in another browser. To handle these use cases, Spring security provides an option where we can show error message to the second attempt instead of forcing the original user to be logged out. We can enable this feature with help of maxSessionsPreventsLogin.

@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
            .maxSessionsPreventsLogin(true)
            .maximumSessions(1)
            .expiredUrl("/login?invalid-session=true");
    }
}

Set the value as true for maxSessionsPreventsLogin.You have to be careful while trying to use this approach.

  1. If user close the window without hitting the logout button, they won’t be able to login again until the session time out.
  2. This happens because it removes the JSESSIONID on closing the browser window, however you are still logged in user for the underlying application.

For more information, read the spring security documentation.

3.4. Concurrency Control – Common Issue

With maximumSessions method, keep in mind few important points as it can cause lots of confusion and issues if you are not clear on few details

  1. If you are using the custom UserDetails instance, make sure you override equals() and hashCode() methods.
  2. By default Spring security SessionRegistry  implementation uses an in-memory map to store the UserDetails. If you are using a custom UserDetails without equals() and hashCode() methods, it won’t be able to match the user correctly. Also, the default UserDetails object from Spring security provides implementation for both equals() and hashCode() methods.
  3. If Spring security remember me feature is used for the login, the concurrency control is not enforced.
  4. In a clustered environment, the default concurrency control will not work as the SessionRegistry is in-memory implementation. The user login will be server specific and the same user can login again if they try to login on the other server on the cluster. You can use the Spring Session to handle this issue with the help of a custom SessionRegistry
  5. If the application server restart, the SessionRegistry will be empty (remember it’s an in-memory map) but users who were already logged in with a valid session are logged in. This will create a conflict where the user is logged in but spring security will mark user as not logged in. We can also resolve this with the help of custom SessionRegistry to load the data from the central location.

Summary

In this article we talked about the spring security session management and how to control the session with spring security. To summarize, we talked about the following important points in this article.

  1. How spring security manage the session and how to control the session creation strategy with spring security.
  2. how to the concurrency control works with spring security.
  3. How to configure number of concurrent sessions per user.
  4. Limitation with the spring security concurrency control and few options to customize it.