1

I'm working with a custom STS based on WIF (.NET 4.0) that is currently used only for SharePoint applications. I have sliding expiration code set up in an HTTP module that works as expected, except the life time of the security token is 10 hours (default life time).

/// <summary>
/// Handles the SessionSecurityTokenReceived event of the SingleSignOnModule 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>
private void SingleSignOnModule_SessionSecurityTokenReceived(Object sender, SessionSecurityTokenReceivedEventArgs e)
{
    using (new SPMonitoredScope("SingleSignOnModule-SessionSecurityTokenReceived"))
    {
        if ((HttpContext.Current != null) && (FederatedAuthentication.SessionAuthenticationModule != null) && (e != null))
        {
            TimeSpan logonTokenCacheExpirationWindow = TimeSpan.FromSeconds(1);
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                logonTokenCacheExpirationWindow = SPSecurityTokenServiceManager.Local.LogonTokenCacheExpirationWindow;
            });

            DateTime currentDateTime = DateTime.UtcNow;
            TimeSpan sessionLifetime = (e.SessionToken.ValidTo - e.SessionToken.ValidFrom);
            DateTime sessionValidFrom = e.SessionToken.ValidFrom;
            DateTime sessionValidTo = (e.SessionToken.ValidTo - logonTokenCacheExpirationWindow);

            if ((currentDateTime < sessionValidTo) && (currentDateTime > sessionValidFrom.AddMinutes(sessionLifetime.TotalMinutes / 2)))
            {
                e.SessionToken = FederatedAuthentication.SessionAuthenticationModule.CreateSessionSecurityToken(e.SessionToken.ClaimsPrincipal, e.SessionToken.Context, currentDateTime, currentDateTime.AddMinutes(sessionLifetime.TotalMinutes), e.SessionToken.IsPersistent);
                e.ReissueCookie = true;
            }
        }
    }
}

Initially, I thought this could just be set by SPSecurityTokenServiceManager. However, this changed nothing. (PowerShell snippet)

Write-Output("[INFO] Updating the SPSecurityTokenServiceManager")
$stsMgr = Get-SPSecurityTokenServiceConfig

Write-Output("[INFO] Updating the SPSecurityTokenServiceManager to use session cookies.")
$stsMgr.UseSessionCookies = $true; #

Write-Output("[INFO] Updating the SPSecurityTokenServiceManager logon token cache expiration window")
$stsMgr.LogonTokenCacheExpirationWindow = New-TimeSpan -Days 0 -Hours 0 -Minutes 1

Write-Output("[INFO] Updating the SPSecurityTokenServiceManager service token cache expiration window.")
$stsMgr.ServiceTokenCacheExpirationWindow = New-TimeSpan -Days 0 -Hours 0 -Minutes 20

$stsMgr.Update()

I'm unable to set SessionSecurityTokenHandler.DefaultLifetime as it's read-only and set to 10hrs.

// Type: Microsoft.IdentityModel.Tokens.SecurityTokenHandler
// Assembly: Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// Assembly location: C:\Windows\assembly\GAC_MSIL\Microsoft.IdentityModel\3.5.0.0__31bf3856ad364e35\Microsoft.IdentityModel.dll

namespace Microsoft.IdentityModel.Tokens
{
    public class SessionSecurityTokenHandler : SecurityTokenHandler
    {
        public static readonly TimeSpan DefaultLifetime = TimeSpan.FromHours(10.0);
        ...
    }
}

The SecurityToken.ValidTo only has a getter not a setter.

// Type: System.IdentityModel.Tokens.SecurityToken
// Assembly: System.IdentityModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\System.IdentityModel.dll

namespace System.IdentityModel.Tokens
{
    /// <summary>
    /// Represents a base class used to implement all security tokens.
    /// </summary>
    /// <filterpriority>2</filterpriority>
    public abstract class SecurityToken
    {
        ...

        /// <summary>
        /// Gets the last instant in time at which this security token is valid.
        /// </summary>
        /// 
        /// <returns>
        /// A <see cref="T:System.DateTime"/> that represents the last instant in time at which this security token is valid.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        public abstract DateTime ValidTo { get; }

        ...
    }
}

I also noticed that in the FederatedAuthentication.SessionAuthenticationModule.CreateSessionSecurityToken, the default ValidTo property is set to the ValidFrom + the default token lifetime. The only way that I can see to set the SecurityToken.ValidTo is when creating the security token. Does this mean I need to implement a custom SecurityToken class or is there somewhere in the WIF stack I can intercept the creation of the token? So far, I only seem to have found the following event handler, FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenCreated, but at this point the token has already been created and in there I can access the token, but as expected the SecurityToken.ValidTo property is only a getter.

As well the <microsoft.identityModel /> config section does not appear to have a setting for this. There is a persistenLifeTime setting, but this is only for cookies written to disk.

<microsoft.identityModel>
      <federatedAuthentication>
        <wsFederation
            persistentCookiesOnPassiveRedirects="true" />
        <cookieHandler 
          persistentSessionLifetime="60.0:0:0" />
      </federatedAuthentication>
</microsoft.identityModel>

Also, to enable encryption/decryption to be server agnostic, the encryption uses a certificate. To do this, I add programatically to the session security token handlers in the Global.asax of my federation provider. I only mention this because I'm wondering, if I need to customize the SecurityToken.ValidTo, do I maybe need to create a custom security token handler class or is how I'm currently doing it in the Global.asax fine and I need to look elsewhere to solve the SecurityToken.ValidTo issue?

  <microsoft.identityModel>
    <service>
      <serviceCertificate>
        <certificateReference x509FindType="FindByThumbprint" findValue="myThumbPrint" />
      </serviceCertificate>
      ...
  </microsoft.identityModel>

namespace MyCompany.IdentityServer.FederationProvider
{
    public class Global : System.Web.HttpApplication
    {
        /// <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>
        protected void Application_Start(object sender, EventArgs e)
        {
            FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;
        }

        /// <summary>
        /// Called when [service configuration created].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs"/> instance containing the event data.</param>
        private void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
        {
            // The session security token handler needs to be overridden so that encryption/decryption is not server dependent via DPAPI.
            // We need encryption/decryption to be server agnostic, so we make it certificate based instead.
            // See http://blogs.msdn.com/b/distributedservices/archive/2012/10/29/wif-1-0-id1073-a-cryptographicexception-occurred-when-attempting-to-decrypt-the-cookie-using-the-protecteddata-api.aspx

            // Use the <serviceCertificate> to protect the cookies that are
            // sent to the client.
            var sessionTransforms =
                new List<CookieTransform>(new CookieTransform[] {
                new DeflateCookieTransform(), 
                new RsaEncryptionCookieTransform(e.ServiceConfiguration.ServiceCertificate),
                new RsaSignatureCookieTransform(e.ServiceConfiguration.ServiceCertificate)  });

            var sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());

            // This does nothing
            //sessionHandler.TokenLifetime = someLifeTime;

            e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
        }
    }
}

If I create a custom securityTokenHandler, I see that I can specify a lifetime, but this looks like what I tried in my Global.asax above, sessionHandler.TokenLifetime = ...

  <microsoft.identityModel>
    <service>
        <securityTokenHandlers>
          <add type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel">
            <sessionTokenRequirement lifetime="TimeSpan" />
          </add>
        </securityTokenHandlers>
      ...
    </service>
</microsoft.identityModel>

I can only assume I'm missing something obvious to set this or is my only course of action to customize to get the SecurityToken.ValidTo I need?

nickytonline
  • 6,855
  • 6
  • 42
  • 76
  • 1
    Why don't you set the lifetime in the STS? – leastprivilege Mar 15 '13 at 05:44
  • Found it hidden in the custom SecurityTokenServiceConfiguration class in the STS. It was hard-coded to 10 hours. Thanks Dominick. – nickytonline Mar 15 '13 at 15:13
  • I posted an answer here http://stackoverflow.com/questions/17099727/expiration-time-buffer-of-sessionsecuritytokenhandler-of-wif-4-5-in-azure-web that shows how to override the "ValidTo" of the SAML from within the Relying Party. Just in case you can't change the STS directly. – Chris Pietschmann May 23 '14 at 19:40

2 Answers2

2

In the STS - set the DefaultTokenLifetime property on the SecurityTokenConfigurationConfiguration class to override the 10h default.

leastprivilege
  • 18,196
  • 1
  • 34
  • 50
0

you can increase it using this powershell script

$sts = Get-SPSecurityTokenServiceConfig
$sts.FormsTokenLifeTime = (New-TimeSpan -minutes <NUMBER_OF_MINUTES>)
$sts.Update()
Get-SPSecurityTokenServiceConfig
Mahmoud Farahat
  • 5,364
  • 4
  • 43
  • 59