9

I'm using ASP authentication and the integrated webservice.

The user logins in with Forms authentication on a login page.
To log out, I call the authentication webservice from Silverlight and call logout.

Everything worked OK but now sometimes IE gets crazy and doesn't log out the user anymore.

I used Fiddler and it turns out that the authentication service returns a SetCookie to clear the ASPXAUTH cookie but on the next call IE still has the cookie set.
So off course because the cookie is there the user is authenticated and logs right back in rather than being directed to the login page.

I checked and didn't see any other description of the issue. I can't reproduce it and my colleagues that have a misbehaving IE have it working fine on one environment and not on the other (one has the issue for DEV and another has the issue for the PreProd server).

Any idea what may be going on?

R4cOOn
  • 2,340
  • 2
  • 30
  • 41
  • One common problem is that the cookie gets set in one context and attempts to be deleted from another. E.g. ensure that the path and domain attributes on the deletion Set-Cookie header exactly match those on the original Set-Cookie call. – EricLaw Dec 08 '10 at 14:23
  • Unfortunately, as I said, I've got no control over that. I call FormsAuthentication.RedirectFromLogin to set the cookie and call the webservice LogOut method. – R4cOOn Dec 08 '10 at 15:22

3 Answers3

6

I had this issue, and to make sure, the user gets logged out, now I use the following piece of code:

        FormsAuthentication.SignOut();

        // Drop all the information held in the session
        Session.Clear();
        Session.Abandon();

        // clear authentication cookie
        HttpCookie cookie1 = new HttpCookie(FormsAuthentication.FormsCookieName, "");
        cookie1.Expires = DateTime.Now.AddYears(-1);
        Response.Cookies.Add(cookie1);

        // clear session cookie
        HttpCookie cookie2 = new HttpCookie("ASP.NET_SessionId", "");
        cookie2.Expires = DateTime.Now.AddYears(-1);
        Response.Cookies.Add(cookie2);

        // Redirect the user to the login page
        Response.Redirect("YourLoginPage.aspx", true);
Adam Vigh
  • 1,260
  • 2
  • 13
  • 20
  • This works. I had an issue where the asp:LoginStatus code would not properly flush, but would redirect to logon.aspx, so I stuck this code in that page_init function and tested for login by if (Context.User.Identity.IsAuthenticated) - at that point the cookies got properly flushed. { – Rob Jun 29 '13 at 12:26
  • For me, the `HttpResponse` object can be reached at: `System.Web.HttpContext.Current.Response.Cookies` – Nate Anderson Feb 07 '22 at 23:08
3

To avoid this issue, the moment you make the SignOut, then the next call must be with Redirect(pageLogOut, true); and stop any other activities until its fully redirect. The parameter true is very important.

After you call the SignOut(), you must force the browser to flush the cookies data because if authenticate request again the cookie for any reason then the cookie is get more time to live and its not delete it from the browser as you ask for with the SigntOut command.

So after the SignOut, make a redirect to a page - or make sure that you flush the cookies to the browser and not ask again anything that have do with the authenticate of the user until the cookies are totally write down to the browser.

Hope this help.

Aristos
  • 66,005
  • 16
  • 114
  • 150
  • MSDN recommends redirect with false then call CompleteRequest to prevent ThreadAbortException. They mention performance as well, but I haven't tested. From [MSDN - Response Redirect](http://msdn.microsoft.com/en-us/library/a8wa7sdt.aspx): If you specify true for the endResponse parameter, this method calls the End method for the original request, which throws a ThreadAbortException exception when it completes. This exception has a detrimental effect on Web application performance, which is why passing false for the endResponse parameter is recommended. – Charles Byrne Feb 25 '13 at 13:37
  • @CharlesByrne If you not stop the processing then is possible more cookie to be written on the browsers, cookies that you do not expect. - take a moment and read this http://stackoverflow.com/a/14641145/159270 – Aristos Feb 25 '13 at 14:51
  • this is not a good general recommendation to make.. or use.. if cookies are being written to the response elsewhere, then that issue should be addressed, not worked around. – Brett Caswell Apr 23 '15 at 17:53
0

It's likely the issue you were experience was in regards to the cookie domain. The cookie maybe written to "." + FormsAuthentication.CookieDomain. I have set cookies to "admin.example.com" domain before, and have seen the cookie prepended with .. In the dev environment, it is written to localhost

The solution I use is to add two cookies for each authentication cookie and session cookie.

So the solution I'm using is as followed:

 protected void SignOut(HttpContext Context)
    {
        FormsAuthentication.SignOut();
        Context.Session.Abandon();

        // clear authentication cookie
        Context.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName)
        {
            Path = FormsAuthentication.FormsCookiePath,
            Value = "",
            Domain = (Convert.ToString(FormsAuthentication.CookieDomain).Length > 0) ? Convert.ToString(FormsAuthentication.CookieDomain) : Context.Request.Url.Host,
            HttpOnly = true,
            Expires = DateTime.Now.AddYears(-1)
        });

        Context.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName)
        {
            Path = FormsAuthentication.FormsCookiePath,
            Value = "",
            Domain = (Convert.ToString(FormsAuthentication.CookieDomain).Length > 0) ? "." + Convert.ToString(FormsAuthentication.CookieDomain) : "." + Context.Request.Url.Host,
            HttpOnly = true,
            Expires = DateTime.Now.AddYears(-1)
        });

        // clear session cookie (not necessary for the current problem but recommended anyway)

        Context.Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId")
        {
            Path = FormsAuthentication.FormsCookiePath,
            Value = "",
            Domain = (Convert.ToString(FormsAuthentication.CookieDomain).Length > 0) ? Convert.ToString(FormsAuthentication.CookieDomain) : Context.Request.Url.Host,
            HttpOnly = true,
            Expires = DateTime.Now.AddYears(-1)
        });


        Context.Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId")
        {
            Path = FormsAuthentication.FormsCookiePath,
            Value = "",
            Domain = (Convert.ToString(FormsAuthentication.CookieDomain).Length > 0) ? "." + Convert.ToString(FormsAuthentication.CookieDomain) : "." + Context.Request.Url.Host,
            HttpOnly = true,
            Expires = DateTime.Now.AddYears(-1)
        });


        FormsAuthentication.RedirectToLoginPage();
    }

The result of this call will add the following headers into the response

Location:/Login.aspx?ReturnUrl=Default.aspx

Set-Cookie:****=; expires=Tue, 12-Oct-1999 05:00:00 GMT; path=/; HttpOnly

Set-Cookie:****=; domain=admin.example.com; expires=Wed, 23-Apr-2014 18:04:58 GMT; path=/; HttpOnly

Set-Cookie:****=; domain=.admin.example.com; expires=Wed, 23-Apr-2014 18:04:58 GMT; path=/; HttpOnly

Set-Cookie:ASP.NET_SessionId=; domain=admin.example.com expires=Wed, 23-Apr-2014 18:04:58 GMT; path=/; HttpOnly

Set-Cookie:ASP.NET_SessionId=; domain=.admin.example.com expires=Wed, 23-Apr-2014 18:04:58 GMT; path=/; HttpOnly

Where *** is the name of my cookie containing my encrypted authentication ticket value;


Note that the first Set-Cookie is likely generated from the FormsAuthentication.SignOut() method call.

Brett Caswell
  • 732
  • 1
  • 4
  • 16