views:

1641

answers:

2

I need to revoke an authentication cookie if the user no longer exists (or some other condition), after the forms authentication mechanism already have received the authentication cookie from the browser and have validated it. I.e. here is the use scenario:

  1. The user have been authenticated, and granted non-expiring auth cookie.
  2. In a few days, the user tries to access my web app again, and as the cookie is valid, the forms authentication mechanism will grant access.

  3. Now I want to perform a second check (whatever condition I want), and decide if I want to let the user continue, or to revoke the authentication.

The question is - is there an official automated way for this? So far I have come with some possibilities, but I do not know which one is better. I can capture the Authenticate event in global.asax, check whatever I want, and to revoke I clear the cookie, and then one of these:

  1. Redirect again to same url - this should work, as this time the forms authentication will fail, and it will redirect to logon page.

  2. Throw some exception ??? which one to make the redirect happen w/o me specifying anything?

  3. Somehow to get the logon page url from the config file (any ideas how/which config handler to use) and redirect directly?

  4. Some FormsAuthentication class/method I have overlooked, which is designed for this?

  5. Any other idea?

+1  A: 

I don't think there is an automated way to achive this. I think the best way would be to add a date to the auth cookie which will be the last time you checked whether the user exists. So when a user logs-in you'll:

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                1, // Ticket version
                name, // Username associated with ticket
                DateTime.Now, // Date/time issued
                DateTime.Now.AddMonths(1), // Date/time to expire
                true, // "true" for a persistent user cookie
                DateTime.Now.ToUniversalTime(), // last time the users was checked
                FormsAuthentication.FormsCookiePath);// Path cookie valid for

        // Encrypt the cookie using the machine key for secure transport
        string hash = FormsAuthentication.Encrypt(ticket);
        HttpCookie cookie = new HttpCookie(
            FormsAuthentication.FormsCookieName, // Name of auth cookie
            hash); // Hashed ticket

        cookie.HttpOnly = true;

        // Set the cookie's expiration time to the tickets expiration time
        if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
        //cookie.Secure = FormsAuthentication.RequireSSL;
        Response.Cookies.Add(cookie);

Then everytime a user is authenicated you can check the additional date you passed to the Authentication ticket and in 10 minute intervals or less double check against the database whether the user exists. The code might look something like this:

public void FormsAuthentication_OnAuthenticate(object sender, 
                           FormsAuthenticationEventArgs args)
    {
        if (FormsAuthentication.CookiesSupported)
        {
            if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
            {
                try
                {
                    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(
                      Request.Cookies[FormsAuthentication.FormsCookieName].Value);

                    DateTime lastCheckedTime = DateTime.TryParse(ticket.UserData);
                    TimeSpan elapsed = DateTime.Now - lastCheckedTime;
                    if (elapsed.TotalMinutes > 10)//Get 10 from the config
                    {
                        //Check if user exists in the database. 
                        if (CheckIfUserIsValid())
                        {
                            //Reset the last checked time
                            // and set the authentication cookie again
                        }
                        else
                        {
                            FormsAuthentication.SignOut();
                            FormsAuthentication.RedirectToLoginPage();
                            return;
                        }
                    }

                }
                catch (Exception e)
                {
                    // Decrypt method failed.
                }
            }
        }
    }

You can even cache the users that have been deleted the last 10 minutes and check against that collection.

Hope that helps.

marto
Yep, the RedirectToLoginPage was the thing I was after ... I did not find it, as this is 1.1 project. I'll need to migrate. Thanks.
Sunny
A: 

If you are rejecting the cookie for some other reason than an expired session, then I think you should redirect the user to a page that describes what they need to do in order to gain access. If logging on again is sufficient, then the logon page would suffice. It sounds, however, like there are conditions under which simply logging on again is not possible. In those cases, it would be better to redirect the user to a suitable error page that describes why they are unable to access the site and explains how to gain access again (if possible).

tvanfosson