Archive

Archive for January, 2011

SharePoint 2010: Set session timeout and setup sliding sessions on an FBA enabled site

January 10, 2011 48 comments

[Updated 12th of Sept 2012]

Please note that the below method is now redundant as long as you have SP 2010 April 2011 Cumulative Update installed. For more details please read this excellant blog post by Shawn Cicoria.

You can get the same to work now by running the PowerShell script below:

$sts = Get-SPSecurityTokenServiceConfig
$sts.FormsTokenLifetime = (New-TimeSpan -Minutes 60)
$sts.LogonTokenCacheExpirationWindow = (New-TimeSpan –Minutes 60)
$sts.Update()

This creates a sliding session effect whereby as soon as there is any activity before the expiry of the token it (the token) is renewed and it will usually only expire if there is 60 minutes of inactivity. If you do not have the SP 2010 April 2011 Cumulative Update installed then you can setup sliding session by following the original blog post below.

[Original Blog Post]

After struggling with this for a few days I finally figured out how to control this in SharePoint 2010.

In MOSS 2007 if you had a site that had windows authentication then you could specify the timeout by adding a timeout attribute in the sessionState element in your web.config. On the other hand if you had an FBA enabled site and wanted to control the session timeout you would do that by adding a timeout attribute in the forms element in the web.config.

The Problem

The problem is that in SharePoint 2010 the same thing does not work for a FBA enabled site. I spent a whole lot of time trying to search for a solution and ended up trying a lot of different things but nothing seemed to work. At one point I came across the powershell script below and thought I had finally found a solution:

$sts = Get-SPSecurityTokenServiceConfig
$sts.WindowsTokenLifetime = (New-TimeSpan -Minutes 60)
$sts.FormsTokenLifetime = (New-TimeSpan -Minutes 60)
$sts.Update()

However, soon I realised that this was causing the session to expire after 60 minutes regardless of the activity of the user. Eventually, I came across this very useful blog post.

The Solution

First of all we need to add some code behind to the Global.asax file of the SharePoint Web Application.

In your Visual Studio project add a new class file and call it Global.asax.cs (you can call it anything really) Then we need to add the following code to the Global.asax.cs file:

namespace MyNameSpace
{
    public class Global : SPHttpApplication
    {
        /// <summary>
        /// Executes custom initialization code after all event handler modules have been added.
        /// </summary>
        public override void Init()
        {
            FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived += new EventHandler<SessionSecurityTokenReceivedEventArgs>(SessionAuthenticationModule_SessionSecurityTokenReceived);
            base.Init();
        }

        /// <summary>
        /// Handles the Start event of the Application control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void Application_Start(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// Handles the SessionSecurityTokenReceived event of the SessionAuthenticationModule control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Microsoft.IdentityModel.Web.SessionSecurityTokenReceivedEventArgs"/> instance containing the event data.</param>
        void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
        {
            // the timeout comes from the web.config
            int configuredTokenTimeout = Convert.ToInt32(ConfigurationManager.AppSettings["SessionTokenTimeout"]);

            DateTime now = DateTime.UtcNow;
            DateTime validFrom = e.SessionToken.ValidFrom;
            DateTime validTo = e.SessionToken.ValidTo;

            long timeLeft = e.SessionToken.ValidTo.Subtract(now).Ticks;
            TimeSpan tokenLifeTime = validTo.Subtract(validFrom);
            TimeSpan configuredTokenTimeSpan = new TimeSpan(0, configuredTokenTimeout, 0);
            // 37200000000 = 62 minutes
            if ((tokenLifeTime.Ticks > configuredTokenTimeSpan.Ticks) || (timeLeft * 2) < tokenLifeTime.Ticks)
            {
                SPSessionAuthenticationModule spsam = sender as SPSessionAuthenticationModule;
                e.SessionToken = spsam.CreateSessionSecurityToken(e.SessionToken.ClaimsPrincipal, e.SessionToken.Context,
                    now, now.AddMinutes(configuredTokenTimeout), true);
                e.ReissueCookie = true;
            }
        }
    }

Next we need to link this code behind to the Global.asax file.

Browse to the root of your Web Application Folder and open up the Global.asax file and add the following (modify the application tag with your specific assembly details):

<%@ Assembly Name="Microsoft.SharePoint"%>
<%@ Application Language="C#" Inherits="MyNameSpace.Global,MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d4469032123b3e99a"%> 

Deploy your solution.

In the example above I am subscribing to the SessionSecurityTokenReceived event. In it I have some custom logic to implement a sliding session. Basically what I am doing is that I discard the original session token (which always seems to have a lifetime of 10 hours) and I create a new session token that has the lifetime I want. In my implementation I also added a key in the appsettings section of the web.config that controls the session timeout value:

  <appSettings>
    .......
    <add key="SessionTokenTimeout" value="60" />
    .........

Finally, I found that you need to run the following powershell script below as well to make the whole thing work:

$sts = Get-SPSecurityTokenServiceConfig
$sts.LogonTokenCacheExpirationWindow = (New-TimeSpan –seconds 1)
// set it to false for better client integration (thanks to Anirudh for pointing this out)
$sts.UseSessionCookies = $false
$sts.Update()
iisreset 

This is the only way I found that allowed me to control the Session Timeout in 2010. Please feel free to leave a comment if you have found a better and easier solution.

Advertisements