none
Passive sign in with sliding expiration

    Question

  • I have a working web app with passive login, custom STS with ASP .NET forms authentication, and relying party services being called by the web app using delegation to act as the signed in user. Basing code off of the Geneva Framework samples, I have all of this working.

    Now a question: Is there any way to enable sliding expiration of the passive login at the web app? I don't mean sliding expiration of the forms authentication at the STS, but at the actual relying party web app. It seems that if the token lifetime is 15 minutes, then 15 minutes after logging in the user is redirected back to the STS regardless of their activity (that is, not 15 minutes after they last accessed a page). This is a problem because a user who is active and hitting a new page frequently will still lose any postback data every 15 minutes.

    Is there a built in way to enable sliding expiration? Is there a way for the relying party web app to make a service call to the STS to extend the life of the token (I see by reflecting that the Renew method on Geneva's base SecurityTokenService class just throws an Exception though)? I do also see by reflection that the default token lifetime is 10 hours, which is longer than a user will be actively using a web app anyway, but it seems like there should be a better way around this issue.

    Any insight would be greatly appreciated.

    Andy
    Monday, November 03, 2008 9:32 PM

Answers

  • Sliding expiration is supported by handling the SessionSecurityTokenReceived event raised by the session authentication module. In that event you can create a new session token, which will be used for validation and saved as a cookie for subsequent validation. Just reset the ValidTo property of the token.

    Sample:
        void SessionAuthentication_SessionSecurityTokenReceived( object sender, Microsoft.IdentityModel.Web.SessionSecurityTokenReceivedEventArgs e )  
        {  
            Microsoft.IdentityModel.Tokens.SessionSecurityToken sessionToken = e.SessionToken;  
            if ( sessionToken.ValidTo > DateTime.UtcNow )  
            {  
                e.SessionToken = new Microsoft.IdentityModel.Tokens.SessionSecurityToken(  
                    sessionToken.ClaimsPrincipal,  
                    sessionToken.SessionId,  
                    sessionToken.Id,  
                    sessionToken.Context,  
                    sessionToken.KeyGeneration,  
                    sessionToken.Key,  
                    sessionToken.ValidFrom,  
                    DateTime.UtcNow.AddSeconds( 10 ),  
                    sessionToken.BootstrapTokens );  
                e.ReissueCookie = true;  
            }  
            else  
            {  
                System.Diagnostics.Debug.WriteLine( "Token expired" );  
            }  
        }  
     

    • Marked as answer by andyjeigh Friday, November 07, 2008 7:54 PM
    Wednesday, November 05, 2008 7:17 PM
    Moderator

All replies

  • Hi Andy,

    What are you using to sign in?

    Are you using the FederatedPassiveSignInControl?
    .. or the SessionAuthenticationModule + WSFederationAuthenticationModule HTTP modules?
    Wednesday, November 05, 2008 10:13 AM
  • Sliding expiration is supported by handling the SessionSecurityTokenReceived event raised by the session authentication module. In that event you can create a new session token, which will be used for validation and saved as a cookie for subsequent validation. Just reset the ValidTo property of the token.

    Sample:
        void SessionAuthentication_SessionSecurityTokenReceived( object sender, Microsoft.IdentityModel.Web.SessionSecurityTokenReceivedEventArgs e )  
        {  
            Microsoft.IdentityModel.Tokens.SessionSecurityToken sessionToken = e.SessionToken;  
            if ( sessionToken.ValidTo > DateTime.UtcNow )  
            {  
                e.SessionToken = new Microsoft.IdentityModel.Tokens.SessionSecurityToken(  
                    sessionToken.ClaimsPrincipal,  
                    sessionToken.SessionId,  
                    sessionToken.Id,  
                    sessionToken.Context,  
                    sessionToken.KeyGeneration,  
                    sessionToken.Key,  
                    sessionToken.ValidFrom,  
                    DateTime.UtcNow.AddSeconds( 10 ),  
                    sessionToken.BootstrapTokens );  
                e.ReissueCookie = true;  
            }  
            else  
            {  
                System.Diagnostics.Debug.WriteLine( "Token expired" );  
            }  
        }  
     

    • Marked as answer by andyjeigh Friday, November 07, 2008 7:54 PM
    Wednesday, November 05, 2008 7:17 PM
    Moderator
  • Jesper, I am using the HTTP modules.

    Peter, thanks for the info. Are there plans to build that in to the Geneva Framework via configuration?

    Also, I guess this doesn't matter too much in the end right now because I can't figure out a way to set the token timeout when using the FederatedPassiveTokenService control, so it uses the default of 10 hours.

    Thanks again for the help!
    Friday, November 07, 2008 8:00 PM
  • Is there a way to control the intial value of the ValidTo property of the SessionSecurityToken from the STS?

    In my STS code I have reduced the lifetime of the token from the default 10 hours, to 1 minute (for testing purposes), but when entering the event mentioned above the ValidTo value of the session security token remains 10 hours, which means the RP will not go back to the STS to check the token, although it has expired?





    Yossi Dahan
    • Edited by Yossi Dahan Monday, December 01, 2008 11:57 AM Clarified question
    Monday, December 01, 2008 10:25 AM
  • There are hooks to specifiy token lifetime - either in SecurityTokenServiceConfiguration or SecurityTokenService.GetLifeTime

    http://www.leastprivilege.com/SAMLTokenCreationInAGenevaSTS.aspx

    HTH
    Dominick Baier - http://www.leastprivilege.com
    Tuesday, December 02, 2008 6:00 AM
  • Thanks Dominic, as I've hinted in my entry (probably not clearly enough) I have tried to use both, and while debugging the STS I can see the token lifetime change to what I set (1 minute) the cookie on the RP seems to still be set for 10 hours?

    At the moment I have to have some code in the RPs global.asax to reduce that as per the sample above, but that's far from ideal as it gives the control to the RP, and I want to control that from the STS.
    Yossi Dahan
    Tuesday, December 02, 2008 8:47 AM
  • I am sorry to resurrect this old thread, but this is the info I am looking for.  :-)

    The event handler you wrote looks exactly like what I want, but I'm not sure where to add the delegate!

    I put the code below in the Application_Start() of my global.asax, but the event is never triggered.

    var sam = new SessionAuthenticationModule();
            sam.SessionSecurityTokenReceived +=
                new EventHandler<SessionSecurityTokenReceivedEventArgs>(sam_SessionSecurityTokenReceived);

    It's likely that I'm doing this wrong.  Could you please provide to me how to create the delegate so that this event gets trapped?

    thanks!
    Rich

    Friday, April 29, 2011 11:37 PM
  • It's called in Global.asax via module/event naming convention.   Put the following in global.asax:

     

     

    ///<summary>

            ///This event occurrs when a session security token has been read from a cookie. 

            ///Sliding expiration is supported by handling this event.  This event is raised by 

            ///the session authentication module. In this event you can create a new session token, 

            ///which will be used for validation and saved as a cookie for subsequent validation. 

            ///Just reset the ValidTo property of the token.                

            ///</summary>

            ///        

            protected void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs args)

            {

      .

      .

      .

      }

     

    This corresponds with the following module registration in web.config:

     

    <httpModules>

          <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

    .

    .

     

     

     

     

     


    • Edited by scott_m Saturday, April 30, 2011 1:33 AM more detail
    Saturday, April 30, 2011 1:31 AM
  • Hi, Scott,

    Thanks for your reply. I have thatentry in my web.config and I pasted the event handler into my global.asax.  The event never gets fired.  I wonder if there is some step not mentioned here. 

    Thanks a lot for your help!

    Rich

    Monday, May 02, 2011 3:41 AM
  • I'm not sure what happened but this is working for me now! 

    Thanks a lot for your help!

    Monday, May 02, 2011 6:07 PM
  • Since there has been recent activity on this thread, I'll post :). Thanks, this helped a lot. Following is what I came up with to ensure that when the cookie expires the user has to login again. It feels backward though that the RP has to enforce this.

    Global.asax.cs:

    protected void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
        {
          WSFederationHelper.Instance.PassiveSignOutWhenExpired(e.SessionToken, this.Request.Url);
        }
    

    Helper class:

     /// <summary>
      /// RP federation helper.
      /// </summary>
      public class WSFederationHelper : IWSFederationHelper
      {
        private static readonly IWSFederationHelper _default = new WSFederationHelper();
        /// <summary>
        /// Singleton instance.
        /// </summary>
        public static IWSFederationHelper Instance
        {
          get
          {
            return _default;
          }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        private WSFederationHelper()
        {
        }
        /// <summary>
        /// Logout the user.
        /// </summary>
         public void PassiveSignOut(Uri aUri)
        {
          Contract.Requires(aUri != null);
          WSFederationAuthenticationModule authModule = FederatedAuthentication.WSFederationAuthenticationModule;
          //make sure we can handle absolute Uri's as well.
          if (aUri.IsAbsoluteUri)
          {
            aUri = aUri.MakeRelativeUri(new Uri(authModule.Realm));
          };
          FederatedAuthentication.SessionAuthenticationModule.CookieHandler.Delete();
          FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie();
          string signoutUrl = (WSFederationAuthenticationModule.GetFederationPassiveSignOutUrl(authModule.Issuer, authModule.Realm, null));
          //new Uri(authModule.Issuer)
          WSFederationAuthenticationModule.FederatedSignOut(new Uri(signoutUrl), new Uri(authModule.Realm + aUri.OriginalString)); 
        }
        /// <summary>
        /// Automatically sign-out when the token <paramref name="aToken"/> has expired. Redirect to the given <paramref name="aUri"/> and perform a new authentication if required.
        /// </summary>
           public void PassiveSignOutWhenExpired(SessionSecurityToken aToken, Uri aUri)
        {
          Contract.Requires(aToken != null);
          Contract.Requires(aUri != null);
          if (aToken.ValidTo < DateTime.UtcNow)
          {
            PassiveSignOut(aUri);
          }
          
        }
      }
    

     

     

    Friday, May 06, 2011 10:36 PM
  • mrent - Can you include IWSFederationHelper, and more information about Contract, etc?

     

    This is interesting code...

    Monday, November 14, 2011 4:29 PM
  • Can you please include the IWSFederationHelper interface which you have used in your programming.
    Tuesday, January 31, 2012 8:53 AM