简体   繁体   中英

MVC4 - Setting custom user data in forms authentication ticket causes the forms authentication cookie to not get set?

My legacy MVC4 application uses forms authentication. When I try to create the following custom FormsAuthenticationTicket the cookie is returned in the response but never set by the browser. Note that I am trying to store an OpenID Connect id_token in the cookie, relying on the encryption that the FormsAuthenticationTicket class offers.

//Yes you can decode it - it's just test data
string idToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA1M2JjYTgzNzZmZjhlNTM5MWVkYzMxYWJkMjU5YzBjIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDc1ODExMjcsImV4cCI6MTUwNzU4MTQyNywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiaW1wbGljaXQiLCJub25jZSI6IjE1MDc1ODExMjA5MDMwMDQ0MDUzNDkzNjk3ODUzMTYiLCJpYXQiOjE1MDc1ODExMjcsImF0X2hhc2giOiJVWm5SeU1pXzVyUEN6NWduYmt5c09BIiwic2lkIjoiOTExYjI1OGQ5OGNiYzRlYzVkYTFiNmFkYzhiMmRjNTUiLCJzdWIiOiIxIiwiYXV0aF90aW1lIjoxNTA3NTgxMTI3LCJpZHAiOiJsb2NhbCIsIm5hbWUiOiJ4Iiwid2Vic2l0ZSI6Imh0dHBzOi8vYWxpY2UuY29tIiwicm9sZSI6ImFkbWluIiwibW9kZWxBY2Nlc3MiOlsiMTIzNCIsIjU2NzgiXSwiY29ubmVjdGlvblN0cmluZyI6InNvbWVNb2RlbENvbm5lY3Rpb25TdHJpbmciLCJhbXIiOlsicHdkIl19.SwTIU1dP1FifCcXVNHkbIGshQiGIjfaa7UAWOrtqKb-FqMMrkvJx_Wa3W19r6NeNwc8mo2go6AFwwu_WM0TF1VJBO1pfmvX35oKgjdTTSqrSmMo5R9_rcywm5YKwVYzmvDqRjPfhZksXkIOuTIk3JOemLrKqw6VIHPyFYV6ZYSK6ZxTpxx50Yz90MmEOBDsTc0GZpQbeZmzyDkBe-iD9uVnlPN2UHz_UuMF__yfmzjGROKLpvem36TKSMa1mEJE7DVxJkexmbxQe3CVwZeIU3iPKloabSReaLCJLqINeI0ikGa4x6PbgfjiP1TPVhIP6i8zUp47lSavGgyy0XVFGtQ";

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                            1,
                            model.UserName,
                            DateTime.Now,
                            DateTime.Now.AddDays(30),
                            true,
                            idToken,
                            FormsAuthentication.FormsCookiePath);
                        // Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
this.Response.Cookies.Add(new HttpCookie("TEST", encTicket));

At first I thought the reason for this might be because of the length. But I read the max length for a cookie is 4096 bytes. The idToken is only 983 bytes.

Interestingly enough, if I make the data smaller (change idToken to be 684 bytes) everything works as expected. Here is a working example:

//Shortened the idToken (for the sake of the example)
string idToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA1M2JjYTgzNzZmZjhlNTM5MWVkYzMxYWJkMjU5YzBjIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDc1ODExMjcsImV4cCI6MTUwNzU4MTQyNywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiaW1wbGljaXQiLCJub25jZSI6IjE1MDc1ODExMjA5MDMwMDQ0MDUzNDkzNjk3ODUzMTYiLCJpYXQiOjE1MDc1ODExMjcsImF0X2hhc2giOiJVWm5SeU1pXzVyUEN6NWduYmt5c09BIiwic2lkIjoiOTExYjI1OGQ5OGNiYzRlYzVkYTFiNmFkYzhiMmRjNTUiLCJzdWIiOiIxIiwiYXV0aF90aW1lIjoxNTA3NTgxMTI3LCJpZHAiOiJsb2NhbCIsIm5hbWUiOiJ4Iiwid2Vic2l0ZSI6Imh0dHBzOi8vYWxpY2UuY29tIiwicm9sZSI6ImFkbWluIiwibW9kZWxBY2Nlc3MiOlsiMTIzNCIsIjU2NzgiXSwiY29ubmVjdGlvblN0cmluZyI6InNvbWVNb2RlbENvbm5lY3Rpb25TdHJpbmciLCJhbXIiOlsicHdkIl19.SwTIU1dP1FifCcXVNHkbIGshQiGIjfaa7UAWOrtqKb-";

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                            1,
                            model.UserName,
                            DateTime.Now,
                            DateTime.Now.AddDays(30),
                            true,
                            idToken,
                            FormsAuthentication.FormsCookiePath);
// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
// Create the cookie.
this.Response.Cookies.Add(new HttpCookie("TEST", encTicket));

I am decrypting the data as follows:

HttpCookie cookie = HttpContext.Current.Request.Cookies["TEST"];
if (cookie != null)
{
    Debug.WriteLine("Found Cookie Application_PostAuthenticateRequest");

    // Get the forms authentication ticket.
    FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(cookie.Value);
    if (authTicket == null)
    {
          Debug.WriteLine("auth ticket was null");
    }
    else
    {
          Debug.WriteLine("printing auth ticket");
          Debug.WriteLine(authTicket.UserData);
    }
}
else
{
     Debug.WriteLine("No Cookie Application_PostAuthenticateRequest");
}

Why is the first example not working despite the cookie being well under the maximum limit?

I came across this while looking deep into ASP.NET auth cookies. The underlying reason is that the encoding used by ASP.NET to turn this into a cookie results in your 983b of data taking up 3936b in the final over-the-wire cookie.

The reason is twofold.

1) The ASP.NET cookie serialises strings of data into the cookie payload as UTF-16LE strings. see reference source

This results in your 983b being written as a 7-bit encoded length ( 0x5707 ) followed by 1966b (983 UTF-16LE characters) for a total size before encoding of 1968b, a 2:1 increase in storage.

2) The entire cookie once encrypted is written as a hex string, meaning that each of those 1968b is represented in the final cookie as two characters 0..9A..F (eg: A1B2C3.. ) leading to a total size in the cookie of 3936b, a 4:1 increase in storage.

Then of course there's the rest of the contents in that cookie too like expiration dates, usernames etc meaning that your 983b of data quickly blows out the the 4kb cookie limit.

This would seem to explain the dotnet comment about userdata on the docs page

You should limit the amount of data stored in the UserData property. You must ensure that the size of the UserData property does not result in an invalid cookie or an excessively long URL.

Because it looks like every 1 byte of userdata results in 4 bytes of cookie.

Shared for the ages because i wish this post had existed 48hrs ago.

The problem is that after the encryption has taken place the data is too large. You must limit the amount of data you put into the FormsAuthenticationTicket . If you are within the limit then everything will work as expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM