Scott Hanselman

Accessing the ASP.NET FormsAuthentication "Timeout" Value

May 13, '04 Comments [3] Posted in ASP.NET | Internationalization | XML
Sponsored By

Here's a heck of a thing.  I'm doing my own FormsAuthentication Cookie/Ticket, rather then using the built in FormsAuthentication.RedirectFromLoginPage, as I need support for UserData, and other encrypted goodness.  So, I need to:

    // Create the authentication ticket            
            FormsAuthenticationTicket authTicket = new
                FormsAuthenticationTicket(1, //version
                userName, // user name
                DateTime.Now,             //creation
                DateTime.Now.AddMinutes(??), //Expiration
                false, //Persistent
                userDataGoodness); //Secret Sauce

but, I want to use the Timeout value that is already in the Web.config:

    <authentication mode="Forms">
            <!-- TODO: Set requireSSL to true for production -->
            <forms requireSSL="false"
                slidingExpiration="true"
                loginUrl="~/login.aspx"
                name="AuthenticationTicket"
                protection="All"
                timeout="20" />
        </authentication>

which seems reasonable, eh?  Plus, as I'm a nice guy (hopefully not a hack) I like to do things the Kosher way.  I'd had to hack this up.  So, I figure I'll use something like 'FormsAuthentication.Timeout' - except it doesn't exist.  I can get to everything else, just not the Timeout.

And the Googling and Reflecting begins.  Sometimes I think that's my full time job, Googling and Reflecting.

Here's my thought process, for your edutainment:

  • THOUGHT: Surely they must have thought about this.
  • ANSWER VIA GOOGLE: In a 2002 MSDN Online Chat, someone asked this question and was told: “Unfortunately, we don't expose this configuration property currently.“ but given these helpful tips:
    1. You could try reading it using System.Management
      (ME: But this would require giving WMI access to ASP.NET and doing something like:

      string path = "root\\NetFrameworkV1:forms";
      ManagementObject pm = new ManagementClass(path).CreateInstance();
      pm["Selector"] = "config://localhost"; // represents the machine.config file
      pm.Get();
      Response.Output.WriteLine("timeout = {0}<br>", pm["timeout"]);

      Yuck.)
    2. You can retrieve the value you set by casting User.Identity to an instance of FormsIdentity and accessing the fields on that object.
      (ME: This only allows me to see the result AFTER I've already set it once.  I need this to work the first time, and I'd like to read it as a configuration item, not a side effect.

  • THOUGHT: Someone on Google Groups must have done this before.
  • ANSWER FROM GOOGLE GROUPS: Noone has a clue, but many have hacked things worse that my upcoming hack. NOTE: Don't do this, and remember Scott's Rule of Programming 0x3eA)
    1. Private Function TimeOut_Get() As Integer
      'Get formsauthentication TimeOut value
      'Kludge, timeout property is not exposed in the class
      FormsAuthentication.SetAuthCookie("Username",
      False)
      Dim ticket As FormsAuthenticationTicket =
      FormsAuthentication.Decrypt(Response.Cookies
      (FormsAuthentication.FormsCookieName).Value)
      Dim ts As New TimeSpan(ticket.Expiration.Ticks -
      ticket.IssueDate.Ticks)
      Return ts.Minutes
      End Function

  • THOUGHT: I could just put the configuration somewhere else in my web.config and let folks keep the two in sync.
  • ANSWER FROM MY CONSCIENCE: That would mean that there would be invalid states if they didn't match.

Note, here's where insanity and over engineering set in...

  • THOUGHT: I can just use HttpContext.GetConfig and read it myself.
  • ANSWER VIA REFLECTOR: AuthenticationConfig and all it's properties are internal.

  • THOUGHT: I can use Reflection and read the privates myself. 
    Remember, Relector and a little Red Wine will always give you access to Private Members.
  • ANSWER VIA MY CONSCIENCE: I don't really want to Reflect my way to salvation

  • THOUGHT: Screw it, let's just SelectSingleNode once and feel back for 10 minutes.
  • ANSWER:

                System.Xml.XmlDocument x = new System.Xml.XmlDocument();
                x.Load(UrlPath.GetBasePhysicalDirectory() + "web.config");
                System.Xml.XmlNode node = x.SelectSingleNode("/configuration/system.web/authentication/forms");
                int Timeout = int.Parse(node.Attributes["timeout"].Value,System.Globalization.CultureInfo.InvariantCulture.NumberFormat);

I know it could be better, but I'll put it in a constructor, add some error handling and move on. All this thinking only took about 20 minutes, so don't think I spent the afternoon sweating it.  More time was spent on this post! :)

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Monday, 17 May 2004 00:48:08 UTC
You say that you can get to everything else except the timeout, so how do you get to the loginUrl. I want to redirect the user to the login page in a specific instance, but I can not figure out how to get to the loginUrl in the forms tag without breaking down the url as suggested in this post. Is there another way?
Tuesday, 18 May 2004 20:28:54 UTC
So why do you need the Timeout in your code? Just curious. I rely on the cookie expiring and the result of that showing up in the FormsAuthenticationTicket.Expired Property.
Sunday, 30 May 2004 02:23:01 UTC
Cheat! Use the FormsAuthentication to create a dummy cookie to get the time

FormsAuthentication.SetAuthCookie("get_timeout", true);
DateTime expires = FormsAuthentication.GetAuthCookie("get_timeout", true).Expires;
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.