Too many OpenID.nonce cookies cause “Bad Request”

2019-04-08 10:30发布

问题:

I have already gone through links here, here and here which are related to issue I am having.

I have Silverlight application using IdentiServer3 for authentication and I started having this issue just now when I implemented log out functionality. Note that the issue has nothing to do with Silverlight because login and logout functionality is actually implemented on the server side which is a classic ASP.Net Web form. (.NET 4.5.1)

The application never had logout functionality, so user just used to close the browser so we never encountered this issue before. We have now logout.aspx page and Silverlight application have link to this page.

Logout.aspx page

public partial class Logout : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Request.IsAuthenticated)
        {
            Session.Clear();
            Request.GetOwinContext().Authentication.SignOut();
        }
        Response.Redirect("/");
    }
}

Default.aspx page. This is starting page

public partial class Default : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // Send an OpenID Connect sign-in request.
        if (!System.Web.HttpContext.Current.Request.IsAuthenticated)
        {
            HttpContext.Current.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
        }
    }
} 

OWIN startup class where OpenID connection is configured

  app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Cookies",
            LoginPath = new Microsoft.Owin.PathString("/Default.aspx")
        });

  app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            Authority = ConfigurationManager.AppSettings["Authority"],
            Scope = "openid profile",
            ClientId = ConfigurationManager.AppSettings["ClientId"],
            RedirectUri = ConfigurationManager.AppSettings["RedirectUri"],
            ResponseType = "id_token",
            SignInAsAuthenticationType = "Cookies",

            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                SecurityTokenValidated = (context) =>
                {

                    var id = context.AuthenticationTicket.Identity;

                    // create new identity
                    var newIdentity = new ClaimsIdentity(id.AuthenticationType);

                    // we want to keep username and subjectid                        
                    var sub = id.FindFirst(ClaimTypes.NameIdentifier);
                    var username = id.FindFirst("preferred_username");
                    newIdentity.AddClaim(username);
                    newIdentity.AddClaim(sub);

                    // keep the id_token for logout
                    newIdentity.AddClaim(new Claim("id_token", context.ProtocolMessage.IdToken));

                    context.AuthenticationTicket = new AuthenticationTicket(
                        newIdentity,
                        context.AuthenticationTicket.Properties);

                    return Task.FromResult(0);
                },

                RedirectToIdentityProvider = (context) =>
                {
                    if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
                    {
                        var idTokenHint = context.OwinContext.Authentication.User.FindFirst("id_token").Value;
                        context.ProtocolMessage.IdTokenHint = idTokenHint;
                    }
                    return Task.FromResult(0);
                },                    
            }

Steps to reproduce the issue:

  1. I type web site URL which redirects me to identityserver3 login page.
  2. I enter credentials and hit login.
  3. After successful login I get redirected to the web site and There I click log out.
  4. I get logged out successfully. Fiddler shows the following calls

    https://idsvr.mydomain.com/identity/connect/endsession?id_token_hint=XXXXXXXXXXXXXX https://idsvr.mydomain.com/identity/logout?id=616dd9a4e4c6a55b0bb27faceb4df8dd https://idsvr.mydomain.com/identity/connect/endsessioncallback?sid=xxxxxx

  5. I land up on https://idsvr.mydomain.com/identity/logout?id=xxxxxxx page as expected.

  6. Now I close the browser ( this step is important)
  7. Now type web site URL again which redirects me to identity server login page. ( like Step 1)
  8. I enter credentials and hit login.
  9. After successful login, IdentityServer makes POST to the web site and web site creates AuthenticationTicket. However, here HttpContext.Current.Request.IsAuthenticated is false so Default.aspx page redirects to IdentityServer. I am already logged in so Indetityserver redirects to client web site and loops continue.

Fiddler shows several round trips from identityServer to web site’s default.aspx page. Each roundtrip keeps adding OpenIdConnect.nonce.OpenIdConnect cookie and ultimately i get bad request error because of max request size.

So as suggested in above links I downgraded Microsoft.Owin.Security.OpenIdConnect to 3.0.0 in Client Application.

However, I still get stuck in continuous loop. The only difference is now it does not add new OpenIdConnect.nonce.OpenIdConnect cookie for each round trip. Fiddler shows only one cookie for each round trip. However HttpContext.Current.Request.IsAuthenticated is still false. So I get stuck in continuous loop.

回答1:

I had a similar issue with my asp.net mvc application . After some Research i found that there is a bug in Microsoft's Owin implementation for System.Web. The one that is being used when running Owin applications on IIS. Which is what probably 99% of us do, if we're using the new Owin-based authentication handling with ASP.NET MVC5.

The bug makes cookies set by Owin mysteriously disappear on some occasions.

This middleware is a fix for that bug. Simple add it before any cookie handling middleware and it will preserve the authentication cookies.

app.UseKentorOwinCookieSaver();

Here is the link in detail https://github.com/KentorIT/owin-cookie-saver



回答2:

What solved the problem for me was using AdamDotNet's Custom OpenIdConnectAuthenticationHandler to delete old nonce cookies.

https://stackoverflow.com/a/51671887/4058784