Piercy
Piercy

Reputation: 809

set-cookie not working for IE11/10 after clearing cache

I'm currently experiencing a problem where after clearing cache/cookies IE10 & IE11 will not set the cookie again. The requests and responses look almost identical but after clearing the cache the cookie is never passed up even though it appears to be set correctly.

Heres how my login method flows:

 1. VerifyLogin()    -> Fail: Go To Login page
                     -> Pass: Call rest of the AJAX Methods // Enter Login Credentials and submit
 2. Authentication() -> Fail: Prompt the user
                     -> Pass: set forms auth cookie and navigate back to original page, where it will call VerifyLogin() again

This once Authentication() passes they should then slip through VerifyLogin() with no problem and continue using the product. All the calls will now have the forms authentication cookie passed up.

In the instance im seeing it fail, the Authentication() call passes and gets a 200 OK (and has a set-cookie response header) however, the VerifyLogin() then fails because it hasn't passed up the cookie.

I have had a real hard time reproducing this but so far the reproduction steps i have are as follows. This is starting with no instance of IE running. I'm not 100% sure this is the exact same issue my customers are experiencing however it seems to reveal the same problem they are seeing.

  1. Start IE
  2. Browse to the index page of the site and get bounced to the login (verify failed)
  3. Login with credentials, Authentication() returns a 200 OK and has a set-cookie response header. It then navigates you and calls VerifyLogin() which passes. The cookie is sent up in the request and its all successful. Subsequent calls all work.
  4. Clear my cache and cookies
  5. Browse to the index page of the site and get bounced to the login (verify failed as it should)
  6. Login with credentials, Authentication() returns a 200 OK and has a set-cookie response header. It then navigates you and calls VerifyLogin() at this point fails. The cookie isn't passed up in the request, even though it was previously set in the response of Authentication(). If i close and reopen IE it will work again.

So, its like the second time round the set-cookie response is just not setting the cookie.

Firstly, Heres the relevent sections of my web.config and how i set my forms cookie.

web.config:

 <authentication mode="Forms">
      <forms enableCrossAppRedirects="true" name="Gator.Express.Auth" timeout="2880" />
    </authentication>

setAuthenticationCookie method:

 public void SetAuthenticationCookie(string userName, CookieData cookieData)
        {
            //In order to pickup the settings from config, we create a default cookie and use its values to create a 
            //new one.
            var cookie = FormsAuthentication.GetAuthCookie(userName, true);
            var ticket = FormsAuthentication.Decrypt(cookie.Value);

            if (ticket == null)
                throw new Exception("Error setting authorisation cookie. Decryption of default cookie failed.");

            var jsonToken = JsonConvert.SerializeObject(cookieData);

            var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration,
                ticket.IsPersistent, jsonToken, ticket.CookiePath);
            var encTicket = FormsAuthentication.Encrypt(newTicket);

            cookie.Value = encTicket;

            HttpContext.Current.Response.Cookies.Add(cookie);
        }

Now below here are the requests and responses in order.

Working Authentication Request

POST http://localhost:55733/api/Authentication HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:61496/Login.html
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
Content-Length: 35
DNT: 1
Host: localhost:55733
Pragma: no-cache

Username=michaelGator&Password=XXXX

# Working Authentication Response

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
Set-Cookie: Gator.Express.Auth=01020FCCF4658183D208FE0F4CC8BA1385D208000C6D00690063006800610065006C004700610074006F00720000012F00FF; path=/; HttpOnly
Set-Cookie: Gator.Express.Auth=0102054E17668183D208FE05CEEABA1385D208010C6D00690063006800610065006C004700610074006F007200377B002200530073006F004100630063006F0075006E0074004900640022003A002200300030003000300030003000300030002D0030003000300030002D0030003000300030002D0030003000300030002D0030003000300030003000300030003000300030003000300022007D00012F00FF; expires=Sun, 05-Jul-2015 08:28:39 GMT; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcV29ya2luZ1xnYXRvci5nYXRvcndlYnNlcnZpY2VcU291cmNlXEdhdG9yV2ViU2VydmljZVxhcGlcQXV0aGVudGljYXRpb24=?=
Access-Control-Allow-Origin: http://localhost:61496
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 03 Jul 2015 08:28:39 GMT
Content-Length: 14

"michaelGator"

# Working VerifyLogin Request

GET http://localhost:55733/api/VerifyLogin HTTP/1.1
Referer: http://localhost:61496/
Accept: */*
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
DNT: 1
Host: localhost:55733
Cookie: Gator.Express.Auth=0102054E17668183D208FE05CEEABA1385D208010C6D00690063006800610065006C004700610074006F007200377B002200530073006F004100630063006F0075006E0074004900640022003A002200300030003000300030003000300030002D0030003000300030002D0030003000300030002D0030003000300030002D0030003000300030003000300030003000300030003000300022007D00012F00FF

# Working VerifyLogin response

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcV29ya2luZ1xnYXRvci5nYXRvcndlYnNlcnZpY2VcU291cmNlXEdhdG9yV2ViU2VydmljZVxhcGlcVmVyaWZ5TG9naW4=?=
Access-Control-Allow-Origin: http://localhost:61496
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 03 Jul 2015 08:28:39 GMT
Content-Length: 0

Below here is the non-working set of requests and responses. Note that the Authentication method returns a 200 OK and a set-cookie command but in the next verify login call, the coookie is gone.

# Authentication Request - Returns as it should but part of the non-working set of requests

POST http://localhost:55733/api/Authentication HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:61496/Login.html
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
Content-Length: 35
DNT: 1
Host: localhost:55733
Pragma: no-cache

Username=michaelGator&Password=XXXX

# Authentication Response- Returns as it should but part of the non-working set of requests

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
Set-Cookie: Gator.Express.Auth=01022054EB9B8183D208FE20D4BEF01385D208000C6D00690063006800610065006C004700610074006F00720000012F00FF; path=/; HttpOnly
Set-Cookie: Gator.Express.Auth=01028447109C8183D208FE84C7E3F01385D208010C6D00690063006800610065006C004700610074006F007200377B002200530073006F004100630063006F0075006E0074004900640022003A002200300030003000300030003000300030002D0030003000300030002D0030003000300030002D0030003000300030002D0030003000300030003000300030003000300030003000300022007D00012F00FF; expires=Sun, 05-Jul-2015 08:30:10 GMT; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcV29ya2luZ1xnYXRvci5nYXRvcndlYnNlcnZpY2VcU291cmNlXEdhdG9yV2ViU2VydmljZVxhcGlcQXV0aGVudGljYXRpb24=?=
Access-Control-Allow-Origin: http://localhost:61496
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 03 Jul 2015 08:30:10 GMT
Content-Length: 14

"michaelGator"

# Non-Working VerifyLogin Request - note, no cookie passes up

GET http://localhost:55733/api/VerifyLogin HTTP/1.1
Referer: http://localhost:61496/
Accept: */*
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
DNT: 1
Host: localhost:55733

# Non-Working VerifyLogin response - Fails as no Forms Cookie was passed up

HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcV29ya2luZ1xnYXRvci5nYXRvcndlYnNlcnZpY2VcU291cmNlXEdhdG9yV2ViU2VydmljZVxhcGlcVmVyaWZ5TG9naW4=?=
Access-Control-Allow-Origin: http://localhost:61496
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 03 Jul 2015 08:30:10 GMT
Content-Length: 71

{"$id":"1","Message":"Authorization has been denied for this request."}

Any one have any ideas on this?

Upvotes: 7

Views: 1980

Answers (2)

Keith
Keith

Reputation: 155792

You seem to get getting two authentication cookies, which suggests that your implementation is clashing with something that ASP.Net is trying to automate for you.

There is a FormsAuthentication.SetAuthCookie that creates and sets the cookie, and I think this has already applied, so:

  1. FormsAuthentication.SetAuthCookie gets the cookie (already set in the same response).
  2. Your SetAuthenticationCookie fires.
  3. This calls FormsAuthentication.GetAuthCookie and processes (embeds JSON serialised data into a new cookie) the original.
  4. You call HttpContext.Current.Response.Cookies.Add to create a second cookie.
  5. Both cookies are delivered in the header with the same name

You haven't cleared the original cookie, and .Net doesn't know how to process your processed cookie.

I think you have two options:

  1. Split out your JSON data into a completely separate cookie with a different name.
  2. Roll your own cookies from scratch and don't use any of .Net's FormsAuthentication methods.

I'd personally go with the former as the simplest and quickest to implement.

It might also be worth experimenting with cookie names - I'm not sure all browsers support periods in cookie names, but they are all case sensitive.

Finally something else worth checking - it's almost never worth setting a cookie's path in .Net, as IIS treats URL as case insensitive, but browsers all treat cookie names as case-sensitive.

Upvotes: 2

Alan H.
Alan H.

Reputation: 16588

  1. Why is the response sending two SetCookie headers with the same cookie name? That seems… wrong and confusing.

  2. Be careful not to give IE too much data in cookies. Your cookie values are pretty long! There is a cookie limit of ~4k. That’s total cookies for your domain. If it is longer than that, IE will not send it back.

HTH

Upvotes: 0

Related Questions