Session Management

Introduction

“In human-computer interaction, session management is the process of keeping track of a user's activity across sessions of interaction with the computer system. Typical session management tasks in a desktop environment might include keeping track of which applications are open and which documents each application has opened, so that the same state can be restored when the user logs out and logs in later. For a website, session management might involve requiring the user to re-login if the session has expired (i.e., a certain time limit has passed without user activity). It is also used to store information on the server-side between HTTP requests.” Read more...

This reference describes how the session management is supported in the jWebSocket framework.

What is a jWebSocket session

The session of a custom client in the jWebSocket framework is represented by the WebSocketSession class, every client (connector) has it own instance of this class associated. The WebSocketSession class allows to developers to get the unique session identifier and also use a persistent storage to store session variables. The user session data can be restored if the client gets reconnected after a disconnection produced for example by network connection problems, also if the client gets redirected to the next server node in future server clusters.

 public class WebSocketSession {
   private String sessionId;
   private Map<String, Object> storage;
     ...
 }

The session identifier

“In computer science, a session identifier, session ID or session token is a piece of data that is used in network communications (often over HTTP) to identify a session, a series of related message exchanges. Session identifiers become necessary in cases where the communications infrastructure uses a stateless protocol such as HTTP. For example, a buyer who visits a seller's site wants to collect a number of articles in a virtual shopping cart and then finalize the shopping by going to the site's checkout page. This typically involves an ongoing communication where several webpages are requested by the client and sent back to them by the server. In such a situation, it is vital to keep track of the current state of the shopper's cart, and a session ID is one way to achieve that goal. A session ID is typically granted to a visitor on his first visit to a site. It is different from a user ID in that sessions are typically short-lived (they expire after a preset time of inactivity which may be minutes or hours) and may become invalid after a certain goal has been met (for example, once the buyer has finalized his order, he cannot use the same session ID to add more items). As session IDs are often used to identify a user that has logged into a website, they can be used by an attacker to hijack the session and obtain potential privileges. A session ID is often a long randomly-generated string to decrease the probability of obtaining a valid one by means of a brute-force search. Many servers perform additional verification of the client, in case the attacker has obtained the session ID. Locking a session ID to the client's IP address is a simple and effective measure as long as the attacker cannot connect to the server from the same address. A session token is a unique identifier, usually in the form of a hash generated by a hash function that is generated and sent from a server to a client to identify the current interaction session. The client usually stores and sends the token as an HTTP cookie and/or sends it as a parameter in GET or POST queries. The reason to use session tokens is that the client only has to handle the identifier (a small piece of data which is otherwise meaningless and thus presents no security risk) - all session data is stored on the server (usually in a database, to which the client does not have direct access) linked to that identifier. There are many drawbacks of session id and it's not enough to fulfill the developer requirements. Many developers use other logic to identify the session. Examples of the names that some programming languages use when naming their cookie include JSESSIONID (JSP), PHPSESSID (PHP), and ASPSESSIONID (Microsoft ASP).” Read more...

The WebSocket protocol is built on top of the HTTP protocol, but a WebSocket connection has only one chance to interchange cookies between the client and the server (opening handshake). The jWebSocket engines make usage of the opening handshake to interchange the session identifier in a cookie named “JWSSESSIONID”. During the opening handshake the server expects to receive the JWSSESSIONID cookie from the client to reestablish it stored session, however if the JWSSESSIONID cookie is not present, the server generates one.

For special app requirements, the client can override the session cookie name passing the value as URL argument:
var lURL = "ws://localhost:8787/jWebSocket/jWebSocket;sessionCookieName=SID";
Also a client can start a connection indicating to the server the session id that wants to use:
var lURL = "ws://localhost:8787/jWebSocket/jWebSocket;sessionId=3dckjhsd534blakljtpoih3455gc";

If jWebSocket server runs embedded in a servlet container, the session identifier is obtained from the HttpSession object present in the HttpServletRequest.

The session storage

The session storage represents the session data table used to store the client session variables. Storages in jWebSocket implements the IBasicStorage interface, wish provide a mechanism for store/retrieve data using key-value .

The IBasicStorage interface:

interface IBasicStorage<K, V> extends Map<K, V>, IInitializable { 
    Map getAll(Collection<K> keys) 
      String getName() 
      void setName(String name) 
      } 
      interface IInitializable { 
      void initialize() throws Exception 
      void shutdown() throws Exception 
}

The jWebSocket framework provide IBasicStorage implementations for the following persistent sources:

  • RAM memory (org.jwebsocket.storage.memory.MemoryStorage): Designed for testing purposes only, the data stored in RAM memory and is destroyed if the server gets shutdown.
  • Memcached (org.jwebsocket.storage.memcached.MemcachedStorage): Memcached is a free & open source, high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load. Read more...
  • JDBC (org.jwebsocket.storage.ormlite.OrmLiteStorage): Java Database Connectivity (JDBC) technology is an API for the Java programming language that defines how a client may access a database. It provides methods for querying and updating data in a database. JDBC is oriented towards relational databases. Read more...
  • EhCache (org.jwebsocket.storage.ehcache.EhCacheStorage): Ehcache is an open source, standards-based cache used to boost performance, offload the database and simplify scalability. Ehcache is robust, proven and full-featured and this has made it the most widely-used Java-based cache. It can scale from in-process with one or more nodes through to a mixed in-process/out-of-process configuration with terabyte-sized caches. For applications needing a coherent distributed cache, Ehcache uses the open source Terracotta Sever Array. Read more...
  • MongoDB (org.jwebsocket.storage.mongodb.MongoDBStorageV1, org.jwebsocket.storage.mongodb.MongoDBStorageV2): MongoDB (from "humongous") is a scalable, high-performance, open source NoSQL database. Read more...

 

Each IBasicStorage implementation has the responsibility of data serializing, however a recommended practice is to persist in the session only values with native types like boolean, String, integer.

If jWebSocket server runs embedded in a servlet container, the session storage is obtained wrapping the HttpSession object present in the HttpServletRequest.

Accessing the WebSocketSession instance of a client

The WebSocketConnector class represents the client connection in the jWebSocket framework, each connector instance has a WebSocketSession instance attached.

Example getting the WebSocketSession instance inside a plug-in's processToken method:

  @Override
  public void processToken(PlugInResponse aResponse, 
  WebSocketConnector aConnector, Token aToken) {
	  //The WebSocketSession instance is a property of 
	  //the WebSocketConnector class
	  aConnector.getSession()...
  }

 

The ISessionManager interface

The ISessionManager interface implementations are used by the jWebSocket framework to manage the client sessions while running in standalone mode. The default ISessionManager implementation used by jWebSocket to generate the client session storage and control it expiration, is located in the org.jwebsocket.session.SessionManager class.

The ISessionManager interface:

  interface ISessionManager extends IInitializable {
  IBasicStorage<String, Object> getSession(WebSocketConnector aConnector) 
	throws Exception;
	IBasicStorage<String, Object> getSession(String aSessionId) throws Exception;
	  ISessionReconnectionManager getReconnectionManager();  
	  IStorageProvider getStorageProvider();
	  }

 

The IStorageProvider dependency

The IStorageProvider dependency in the ISessionManager interface represents the component designed to provide the session storage for each WebSocketConnector instance.

The IStorageProvider interface:

	interface IStorageProvider {
	IBasicStorage<String, Object> getStorage(String aName) throws Exception;
	  void removeStorage(String aName) throws Exception;
	  }

 

MemoryStorageProvider Spring configuration example:

  

 

The ISessionReconnectionManager dependency

The ISessionReconnectionManager dependency in the ISessionManager interface represents the component designed to control the client session storage expiration. The default ISessionReconnectionManager implementation used by jWebSocket to control the session storage expiration is located in the org.jwebsocket.session.SessionReconnectionManager class.

The ISessionReconnectionManager interface:

  interface ISessionReconnectionManager {
  Integer getSessionExpirationTime();
  IBasicCacheStorage<String, Object> getReconnectionIndex();
	boolean isExpired(String aSessionId);
	void putInReconnectionMode(String aSessionId);
	IBasicStorage<String, Object> getSessionIdsTrash();
	  IStorageProvider getStorageProvider();	
	  }

 

When a client connection gets stopped, the jWebSocket framework puts it session in reconnection mode, this means: “The client session storage will be protected from expiration until a period of time (expiration time), waiting for a possible reconnection of the client”. To control the session storage expiration the component uses an IBasicCacheStorage instance called “reconnection index” putting inside the client session identifier to be expired after the expiration time, if the client reconnects before the expiration time the session storage is restored, otherwise the storage is cleaned. In the case that the client never reconnects, the reconnection manager also needs to release the session storage used resources (garbage collector). The IBasicStorage named “session ids trash” contains the session identifiers (storage names) of the clients who has assigned a session storage, the “session ids trash” is consulted every 5 minutes by a daemon that removes expired session storages from their persistent source.

Configuring the SessionManager component

The SystemPlugIn in the jWebSocket is the core plug-in that control the client session storage creation and also expiration. During the system load, the SystemPlugIn looks for a Spring bean named “sessionManager” that represents the ISessionManager component.

The following configuration is located in the $JWEBSOCKET_HOME/conf/SystemPlugIn/system.xml file.

RAM storage example:

<bean id="storageProviderMemory" class="org.jwebsocket.storage.memory.MemoryStorageProvider">
</bean>

<bean id="sessionManager" class="org.jwebsocket.session.SessionManager" 
	  init-method="initialize" destroy-method="shutdown">
 <property name="storageProvider" ref="storageProviderMemory"/>
 <property name="reconnectionManager">
	<bean class="org.jwebsocket.session.SessionReconnectionManager" 
	init-method="initialize" destroy-method="shutdown">
		<property name="sessionExpirationTime" value="60" />
		<property name="trashStorageName" value="__session_ids_trash_storage_ns__" />
		<property name="storageProvider" ref="storageProviderMemory"/>
	</bean>
 </property>
</bean>

MongoDB storage example:

<bean id="storageProviderMongoDB" class="org.jwebsocket.storage.mongodb.MongoDBStorageProvider"
   init-method="initialize" destroy-method="shutdown">
 <property name="connection" ref="mongodbConnection0" />
 <property name="databaseName" value="storages" />
 <property name="collectionName" value="__storages_collection__" />
</bean>

<bean id="sessionManager" class="org.jwebsocket.session.SessionManager" 
  init-method="initialize" destroy-method="shutdown">
 <property name="storageProvider" ref="storageProviderMongoDB"/>
 <property name="reconnectionManager">
	<bean class="org.jwebsocket.session.SessionReconnectionManager" 
	  init-method="initialize" destroy-method="shutdown">
		<property name="sessionExpirationTime" value="60" />
		<property name="trashStorageName" value="__session_ids_trash_storage_ns__" />
		<property name="storageProvider" ref="storageProviderMongoDB" />
	</bean>
 </property>
</bean

EhCache storage example:

<bean id="cacheStorageProviderEhCache" class="org.jwebsocket.cachestorage.ehcache.EhCacheCacheStorageProvider">
</bean>

<!-- EhCache session 
<bean id="sessionManager" class="org.jwebsocket.session.SessionManager" 
	init-method="initialize" destroy-method="shutdown">
 <property name="storageProvider" ref="storageProviderEhCache"/>
 <property name="reconnectionManager">
	<bean class="org.jwebsocket.session.SessionReconnectionManager" 
	init-method="initialize" destroy-method="shutdown">
		<property name="sessionExpirationTime" value="60" />
		<property name="trashStorageName" value="__session_ids_trash_storage_ns__" />
		<property name="storageProvider" ref="storageProviderEhCache" />
	</bean>
 </property>
</bean>

JDBC storage example:

<bean id="storageProviderJDBC" class="org.jwebsocket.storage.ormlite.OrmLiteStorageProvider" init-method="initialize">
 <constructor-arg index="0">
  <bean class="com.j256.ormlite.spring.DaoFactory"
	 factory-method="createDao">
	  <constructor-arg index="0" >
		<bean class="com.j256.ormlite.jdbc.JdbcConnectionSource" init-method="initialize">
		 <property name="url">
			<bean class="org.jwebsocket.config.JWebSocketConfig"
				  factory-method="expandEnvAndJWebSocketVars">
				<constructor-arg index="0" value="jdbc:derby:${JWEBSOCKET_HOME}database/sessions;create=true" />
			</bean>
		 </property>
		 <property name="databaseType">
			<bean class="com.j256.ormlite.db.DerbyEmbeddedDatabaseType" />
		 </property>
		</bean>
	  </constructor-arg>
	 <constructor-arg index="1" value="org.jwebsocket.storage.ormlite.EntryEntity" />
	</bean>
 </constructor-arg>
</bean>

<bean id="sessionManager" class="org.jwebsocket.session.SessionManager" 
  init-method="initialize" destroy-method="shutdown">
 <property name="storageProvider" ref="storageProviderJDBC"/>
 <property name="reconnectionManager">
	<bean class="org.jwebsocket.session.SessionReconnectionManager" 
		  init-method="initialize" destroy-method="shutdown">
		<property name="sessionExpirationTime" value="60" />
		<property name="trashStorageName" value="__session_ids_trash_storage_ns__" />
		<property name="storageProvider" ref="storageProviderJDBC" />
	</bean>
 </property>
</bean>

Running in embedded mode

One of the gold features of the jWebSocket framework is the possibility to run in embedded mode, on a servlet container like Jetty or Grizzly or on a custom WebSocketEngine implementation. If jWebSocket server runs inside a servlet container, is recommended to reuse the session mechanism of the servlet container, this means: cookies, the session identifier and the session storage.

Example creating a WebSocketConnector instance using Jetty:

	mConnector = new JettyConnector(mEngine, mRequest, mProtocol, aConnection);
	mConnector.getSession().setSessionId(mRequest.getSession().getId());
	mConnector.getSession().setStorage(new HttpSessionStorage(mRequest.getSession()));

 

The HttpSessionStorage

The HttpSessionStorage is an IBasicStorage implementation wrapper for the HttpSession instance. This storage is used only when jWebSocket server runs inside a servlet container and allows to jWebSocket to re-use the servlet container session persistence layer.

Example running inside Jetty:

 mConnector.getSession().setStorage(new  HttpSessionStorage(mRequest.getSession()));

 

Supported servlet containers

Current supported servlet containers by the jWebSocket framework are:

  • Jetty
  • Grizzly
  • Tomcat

 

Publications

Learn more about WebSockets in general, get background information and gain deeper insight!

Join jWebSocket

Wether developer, designer or translator – join the jWebSocket team and grow together with our success!

Copyright © 2013 Innotrade GmbH. All rights reserved.