2

I have implemented the mix of ASP.Net Cookie Authentication & OWIN OpenId authentication in my application. I am trying to fix a security flaw where the session is not invalidating even after logout.

Middleware Implementation:

app.UseCookieAuthentication(
    new CookieAuthenticationOptions
    {
        AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,    
        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            ClientId = clientId,
            Authority = authority,
        }
     }
);

Log Out Code (Based on user type):

HttpContext.GetOwinContext().Authentication.SignOut(
    OpenIdConnectAuthenticationDefaults.AuthenticationType,
    CookieAuthenticationDefaults.AuthenticationType);
    
HttpContext.GetOwinContext().Authentication.SignOut(
    CookieAuthenticationDefaults.AuthenticationType);

I am capturing the traffic in Fiddler and clicking sign-out from web page. When I try to re-issue the request from Fiddler, it's completing successfully and in HttpModule, the Application.User.Identity.IsAuthenticated is True

I have a couple of questions:-

  1. Is this s Cookie replay attack?
  2. What I am doing wrong, if not I will have to fix it by some hack, like storing a cookie in the cache and comparing it?
Jacob
  • 371
  • 2
  • 18
Rahul Singh
  • 21,585
  • 6
  • 41
  • 56
  • https://learn.microsoft.com/en-us/dotnet/api/system.web.sessionstate.sessionidmanager.removesessionid?view=netframework-4.8 – Jacob Jun 23 '20 at 08:58

2 Answers2

3

When signing out from your application you have to sign out from the Identity server too. Otherwise, your app will be redirected to identity server, get re-authenticated and log back in again. Check the following code snippet under notifications:

app.UseCookieAuthentication(
    new CookieAuthenticationOptions
    {
        AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,    
        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            ClientId = clientId,
            Authority = authority,
        },
        Notifications = new OpenIdConnectAuthenticationNotifications
        {
            RedirectToIdentityProvider = n =>
            {
                // if signing out, add the id_token_hint
                if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
                {
                    var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                    if (idTokenHint != null)
                    {
                        n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                    }
                }

                return Task.FromResult(0);
            }
        }
     }
);

You will find some examples of OWIN Middleware setup (not a direct answer to your question though) here

TejSoft
  • 3,213
  • 6
  • 34
  • 58
  • Thank you for your answer. I am getting `idTokenHint` as null. Is there anything I need to configure? Also, if it's set, I need to check it again or Identity will take care? – Rahul Singh Jun 25 '20 at 22:06
  • You have to add ""id_token" as a claim and so that I can be retrieved back and pass on to id server at the time of logout. Check the example in the link below my answer. It has got a detailed code example. – TejSoft Jun 25 '20 at 23:27
0

Not sure if this answer can help other but, here the link has some more information on how to setup openId with MVC application.

Changing the middleware configuration

Add OpenId & Cookies authentication middleware in startup.cs file. set ResponseType to Id_token to have openId logout too work.

app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                CookieHttpOnly = true,
                AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
                CookieName = "AppCookies",
                ExpireTimeSpan = TimeSpan.FromMinutes(30),
                SlidingExpiration = true
            });

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
    Authority = "https://localhost:44319/identity",
                
    ClientId = "mvc",
    Scope = "openid profile roles",
    RedirectUri = "https://localhost:44319/",
    ResponseType = "id_token",
    SignInAsAuthenticationType = "Cookies",
    UseTokenLifetime = false,
    Notifications = new OpenIdConnectAuthenticationNotifications
    {
        SecurityTokenValidated = n =>
            {
                var id = n.AuthenticationTicket.Identity;

                // we want to keep first name, last name, subject and roles
                var givenName = id.FindFirst(Constants.ClaimTypes.GivenName);
                var familyName = id.FindFirst(Constants.ClaimTypes.FamilyName);
                var sub = id.FindFirst(Constants.ClaimTypes.Subject);
                var roles = id.FindAll(Constants.ClaimTypes.Role);

                // create new identity and set name and role claim type
                var nid = new ClaimsIdentity(
                    id.AuthenticationType,
                    Constants.ClaimTypes.GivenName,
                    Constants.ClaimTypes.Role);

                nid.AddClaim(givenName);
                nid.AddClaim(familyName);
                nid.AddClaim(sub);
                nid.AddClaims(roles);

                // add some other app specific claim
                nid.AddClaim(new Claim("app_specific", "some data"));                   

                n.AuthenticationTicket = new AuthenticationTicket(
                    nid,
                    n.AuthenticationTicket.Properties);
                
                return Task.FromResult(0);    
            },
            RedirectToIdentityProvider = n =>
                {

                    // if signing out, add the id_token_hint
                    if ((int)n.ProtocolMessage.RequestType ==                     (int)OpenIdConnectRequestType.Logout)
                    {
                        var idTokenHint = n.OwinContext.Authentication.User.FindFirst(Startup.IdToken);

                        if (idTokenHint != null)
                        {
                            n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                        }
                    }
                    return Task.FromResult(0);
                }
    }
});

Adding Logout

Adding logout is easy, simply add a new action that calls the Signout method in the Katana authentication manager:

public ActionResult Logout()
{
           Session.Abandon();
    
            // clear session cookie (not necessary for your current problem but i would recommend you do it anyway)
            HttpCookie cookie2 = new HttpCookie("ASP.NET_SessionId", "");
            cookie2.HttpOnly = true;
            cookie2.Expires = DateTime.Now.AddYears(-1);
            Response.Cookies.Add(cookie2);

            // clear site cookie
            var siteCookie = new HttpCookie("AppCookies", "");
            siteCookie.HttpOnly = true;
            siteCookie.Expires = DateTime.Now.AddYears(-1);
            Response.Cookies.Add(siteCookie);
            
            Request.GetOwinContext().Authentication.SignOut();
            return Redirect("/");
}
dev
  • 898
  • 1
  • 13
  • 33