How to use redis session storage with Spring Security?

Stateless architecture plays an important role when a particular user data has to be maintained across all the servers while scaling-out. This session management keeps improving for better results in a scalable environment. Spring session management brings innovation to the Enterprise Java session management space.

Spring Session aims to provide a common infrastructure for managing sessions. This provides many benefits including

  • Accessing a session from any environment (i.e. web, messaging infrastructure, etc.)
  • In a web environment
    • Support for clustering in a vendor neutral way
    • Pluggable strategy for determining the session id
    • Easily keep the HttpSession alive when a WebSocket is active

It is important to understand that Spring session doesn’t depend on the Spring framework at all. Hence can be used in any kind of java frameworks.

Why redis?

Many application servers store HTTP session state in the same JVM that is running application code, since this is simple to implement and fast. When a new app server instance joins or leaves the cluster, the HTTP sessions are rebalanced over the remaining app server instances. In an elastic cloud environment where we are running hundreds of app server instances and where the number of instances can rapidly increase or decrease at any time, we run into a few problems:

  • Rebalancing HTTP sessions can become a performance bottleneck.
  • Large heap sizes needed for storing the large number of sessions can cause garbage collection pauses that impact performance negatively.
  • TCP multicast is usually prohibited by cloud infrastructures but it is frequently used by session managers to discover which app server instances have joined or left a cluster.

Therefore, it is more efficient to store the HTTP session state in a data store outside the JVM running your application code. For example, 100 instances of Tomcat can be configured to use Redis for storing session state, and as the number of Tomcat instances increases or decreases the sessions in Redis are unaffected. Also because Redis is written in C, it can use hundreds of gigabytes of RAM or maybe even terabytes, because there is no garbage collector that gets in the way.

Usage

In Grails we have many plugins for redis session storage, in that we have tried out the below which works perfectly for our scenario.The below plugin saves all the session attributes and restores it even after a server restart. This plugin uses the core spring-session concept for maintaining sessions.

https://grails.org/plugin/spring-session.

This plugin provides spring-session support in grails application. SpringSession provides nice features:

  • HttpSession
    • Clustered Sessions
    • Multiple Browser Sessions
    • RESTful APIs
    • WebSocket

SpringSession uses Redis to persist the HTTP Sessions. You can find official documentation for Spring Session project here:http://docs.spring.io/spring-session/docs/1.0.1.RELEASE/reference/html5/

Currently this plugin provides support for HttpSession only. WebSocket support will be added in further release. These sessions are saved in redis as objects and are retrieved by de-serializing the session attributes.

Pre-requisities:

  • Tested on JDK 8u60, Grails 2.4.3, Redis 3.0.3
  • Tested with Grails Spring Security Plugin 2.0-RC4.
  • Install Redis into the server
  • Start the server and make it available.

Configuration

Just add a plugin in BuildConfig.groovy.

plugins {    runtime ":spring-session:1.0"    ...}

Note: Redis db must be installed on your machine.

Default configuration will lookup Redis server on your localhost port 6379. To override default configuration, add below code in Config.groovy

springsession.redis.connectionFactory.hostName = "<redis server ip>"
springsession.redis.connectionFactory.port = 6379
springsession.redis.connectionFactory.password = "<password>"

Strategy Configuration:

Default session strategy is Cookie based and session cookie name is SESSION You can override the default session strategy

springsession.strategy.defaultStrategy=’HEADER’

This will enable HTTP Header based session strategy. Default token name is x-auth-token you can override this

springsession.strategy.token.headerName = “new token name”

To change default cookie name, add below configuration

springsession.strategy.defaultStrategy.cookie.name=”Your Cookie name”

After configuring the plugin, the session will be stored perfectly in the redis storage. This could be found by cross-checking the spring session Id in redis with the browser session passed in the request as below.

  1. Cookie:

JSESSIONID=62D41BE952A24FA06F7E4337D05639BD; SESSION=417cea57-3a97-4982-8004-6a49584dcb5c

cookieredis

  Redis Values saved for the above example:

redis 127.0.0.1:6379> keys *

1) “spring:session:expirations:1449827220000”

2) “spring:session:sessions: 417cea57-3a97-4982-8004-6a49584dcb5c ”

Saving nested data:

  Change the nested object needed to a JSON String in the backend.

session.example=(Employee.list() as JSON).toString()

Retrieve the same using JSON.parse as below and use the values

def j=JSON.parse(session.example)

Now we have completed learning how to manage sessions outside of your app with zero down time. This will also avoid users’ session log out between the deployments. Redis data is persisted to disk so sessions will survive a server restart providing the ability to share these session across multiple JVMs too.