= Spring Session - Multiple Sessions
Rob Winch
:toc:

This guide describes how to use Spring Session to manage multiple simultaneous browser sessions (i.e Google Accounts).

== Integrating with Spring Session

The steps to integrate with Spring Session are exactly the same as those outline in the link:httpsession.html[HttpSession Guide], so we will skip to running the sample application.

[[users-sample]]
== users Sample Application

The users application demonstrates how to allow an application to manage multiple simultaneous browser sessions (i.e. Google Accounts).

=== Running the users Sample Application

You can run the sample by obtaining the {download-url}[source code] and invoking the following command:

[NOTE]
====
For the sample to work, you must http://redis.io/download[install Redis 2.8+] on localhost and run it with the default port (6379).
Alternatively, you can update the `LettuceConnectionFactory` to point to a Redis server.
====

----
$ ./gradlew :samples:users:tomcatRun
----

You should now be able to access the application at http://localhost:8080/

=== Exploring the users Sample Application

Try using the application. Authenticate with the following information:

* **Username** _rob_
* **Password** _rob_

Now click the **Login** button. You should now be authenticated as the user **rob**.

We can click on links and our user information is preserved.

* Click on the **Link** link in the navigation bar at the top
* Observe we are still authenticated as **rob**

Let's add an another account.

* Return to the *Home* page
* Click on the arrow next to *rob* in the upper right hand corner
* Click **Add Account**

The log in form is displayed again. Authenticate with the following information:

* **Username** _luke_
* **Password** _luke_

Now click the **Login** button. You should now be authenticated as the user **luke**.

We can click on links and our user information is preserved.

* Click on the **Link** link in the navigation bar at the top
* Observe we are still authenticated as **luke**

Where did our original user go? Let's switch to our original account.

* Click on the arrow next to *luke* in the upper right hand corner.
* Click on **Switch Account** -> *rob*

We are now using the session associated with *rob*.

== How does it work?

// tag::how-does-it-work[]

Let's take a look at how Spring Session keeps track of multiple sessions.

=== Managing a Single Session

Spring Session keeps track of the `HttpSession` by adding a value to a cookie named SESSION.
For example, the SESSION cookie might have a value of:

	7e8383a4-082c-4ffe-a4bc-c40fd3363c5e

=== Adding a Session

We can add another session by requesting a URL that contains a special parameter in it.
By default the parameter name is *_s*. For example, the following URL would create a new session:

http://localhost:8080/?_s=1

NOTE: The parameter value does not indicate the actual session id.
This is important because we never want to allow the session id to be determined by a client to avoid https://www.owasp.org/index.php/Session_fixation[session fixation attacks].
Additionally, we do not want the session id to be leaked since it is sent as a query parameter.
Remember sensitive information should only be transmitted as a header or in the body of the request.

Rather than creating the URL ourselves, we can utilize the `HttpSessionManager` to do this for us.
We can obtain the `HttpSessionManager` from the `HttpServletRequest` using the following:

.src/main/java/sample/UserAccountsFilter.java
[source,java,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/java/sample/UserAccountsFilter.java[tags=HttpSessionManager]
----

We can now use it to create a URL to add another session.

.src/main/java/sample/UserAccountsFilter.java
[source,java,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/java/sample/UserAccountsFilter.java[tags=addAccountUrl]
----

<1> We have an existing variable named `unauthenticatedAlias`.
The value is an alias that points to an existing unauthenticated session.
If no such session exists, the value is null.
This ensures if we have an existing unauthenticated session that we use it instead of creating a new session.
<2> If all of our sessions are already associated to a user, we create a new session alias.
<3> If there is an existing session that is not associated to a user, we use its session alias.
<4> Finally, we create the add account URL.
The URL contains a session alias that either points to an existing unauthenticated session or is an alias that is unused thus signaling to create a new session associated to that alias.

Now our SESSION cookie looks something like this:

	0 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e 1 1d526d4a-c462-45a4-93d9-84a39b6d44ad

Such that:

* There is a session with the id *7e8383a4-082c-4ffe-a4bc-c40fd3363c5e*
** The alias for this session is  *0*.
For example, if the URL is http://localhost:8080/?_s=0 this alias would be used.
** This is the default session.
This means that if no session alias is specified, then this session is used.
For example, if the URL is http://localhost:8080/ this session would be used.
* There is a session with the id *1d526d4a-c462-45a4-93d9-84a39b6d44ad*
** The alias for this session is *1*.
If the session alias is *1*, then this session is used.
For example, if the URL is http://localhost:8080/?_s=1 this alias would be used.

=== Automatic Session Alias Inclusion with encodeURL

The nice thing about specifying the session alias in the URL is that we can have multiple tabs open with different active sessions.
The bad thing is that we need to include the session alias in every URL of our application.
Fortunately, Spring Session will automatically include the session alias in any URL that passes through http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#encodeURL(java.lang.String)[HttpServletResponse#encodeURL(java.lang.String)]

This means that if you are using standard tag libraries the session alias is automatically included in the URL.
For example, if we are currently using the session with the alias of *1*, then the following:

.src/main/webapp/index.jsp
[source,xml,indent=0]
----
include::{samples-dir}javaconfig/users/src/main/webapp/index.jsp[tags=link]
----

will output a link of:

[source,html]
----
<a id="navLink" href="/link.jsp?_s=1">Link</a>
----

// end::how-does-it-work[]
