Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom OWIN CookieAuthenticationProvider fails on 1st/cold boot

We have a custom cookie auth provider that puts sets the auth cookie to bear a hostname like .domain.com instead of domain.com or my.domain.com. We do it so the cookies work across all subdomains and the domains. It's as simple as shown below.

Issue

On the very FIRST attempt after app cold start, the cookie STILL bears the domain my.domain.com (our logins are on my.domain.com) DESPITE setting it to .domain.com after executing the SubdomainCookieAuthentication code below (checked with breakpoints). On subsequent login attempts, the cookie hostname is fine.

Question

How can I fix this so it works even on the first attempt?

Code

Custom cookie auth

public class SubdomainCookieAuthentication : CookieAuthenticationProvider
{
    public override void ResponseSignIn(CookieResponseSignInContext context)
    {
        // We need to add a "." in front of the domain name to 
        // allow the cookie to be used on all sub-domains too
        var hostname = context.Request.Uri.Host;
        // works for www.google.com => google.com
        // will FAIL for www.google.co.uk (gives co.uk) but doesn't apply to us
        var dotTrimmedHostname = Regex.Replace(hostname, @"^.*(\.\S+\.\S+)", "$1");
        context.Options.CookieDomain = dotTrimmedHostname;            
        base.ResponseSignIn(context);
    }
}

This is initialized inside the Owin startup class as follows

Class: Startup

File: App_start\Startup.Auth.cs

public void ConfigureAuth(IAppBuilder app) 
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new SubdomainCookieAuthentication()
    });
}
like image 900
DeepSpace101 Avatar asked May 08 '14 18:05

DeepSpace101


1 Answers

I was having the same problem with the Cookie Domain not getting set on the first attempt using the ResponseSignIn method. I was able to resolve this by updating the Owin libraries to 3.x and using the new CookieManager to set the Domain. Found this solution from this post:

How is Owin able to set the Asp.Net Identity authentication cookies after the Application_EndRequest stage?

public class ChunkingCookieManagerWithSubdomains : ICookieManager
{
    private readonly ChunkingCookieManager _chunkingCookieManager;

    public ChunkingCookieManagerWithSubdomains()
    {
        _chunkingCookieManager = new ChunkingCookieManager();
    }

    public string GetRequestCookie(IOwinContext context, string key)
    {
        return _chunkingCookieManager.GetRequestCookie(context, key);
    }

    public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
    {
        options.Domain = context.Request.Uri.GetHostWithoutSubDomain();
        _chunkingCookieManager.AppendResponseCookie(context, key, value, options);
    }

    public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
    {
        options.Domain = context.Request.Uri.GetHostWithoutSubDomain();
        _chunkingCookieManager.DeleteCookie(context, key, options);
    }
}

public static class UriExtensions
{
    public static string GetHostWithoutSubDomain(this Uri url)
    {
        if (url.HostNameType == UriHostNameType.Dns)
        {
            string host = url.Host;
            if (host.Split('.').Length > 2)
            {
                int lastIndex = host.LastIndexOf(".");
                int index = host.LastIndexOf(".", lastIndex - 1);
                return host.Substring(index + 1);
            }
            else
            {
                return host;
            }
        }

        return null;
    }
}

Then, register it in Startup.Auth.cs

app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        ...
        CookieManager = new ChunkingCookieManagerWithSubdomains(), 
        ...
    }
);
like image 110
Austin Avatar answered Sep 27 '22 21:09

Austin