One of the big changes that arrived with the latest version of ASP.NET is the notion of hosting ASP.NET application outside of IIS, this essentially meant there is no reliance on System.Web. For those of us who have been doing large scale ASP.NET development, such an idea borders on the absurd. IIS has sat at the center of the universe for so long, and so this, at first glance, looks like a radical departure from our well-trodden path. The truth of the matter is there are many applications that can and should take advantage of a life cycle without IIS, places where web semantics make a lot of sense but IIS simply does not. As more platforms are supported outside Windows, IIS is just may not exist in any way. This has left a rather a large gap of features embedded within IIS that Web API version 1 relied upon, so this is why the future vision of ASP.NET appears to have abandoned an IIS centric approach, and embraced security with strong consideration for platform agnostic remedies.

Web API V1

A quick look at the following Web API flow diagram we see a significant portion of the authentication story buried within IIS by design (by using HttpModules), which in turn relied on well-established patterns that included Windows and basic authentication.

WebAPI_Security_1Complete

I think it would be fair to say that most developers would probably elect the direct and well-trodden route of relying on IIS to handle authentication but now that ASP.NET and, more specifically, Web API are designed with independent hosting platforms in mind it is clear that a rethink of security implementations is appropriate. It should be noted that the use of HttpMessageHandler was not without some headaches, but as I mentioned IIS provides some very convenient plumbing for things like (user name, threading, client identity). Also as the name suggests HttpMessageHandlers was never specifically designed with authentication in mind.

Web API V2

There are of course two changes here to be aware of (I will include code samples highlighting the differences), the inclusion of the AuthenticationFilter (which for most classic IIS devs will be the biggest noticeable change), and the Host which does not have to be IIS.

  • Host – Now allows for OWIN.
  • Message handlers – Still exists but discouraged for use in security (authentication). It can and should be used for handling more general concerns, things like CORS (cross origin request).
  • Authentication Filters – New, and exist much closer to controller (often used to access security features and logic from OWIN).
  • Authorization filters – Not much has changed here.

WebAPI_Security_2Complete

OWIN Specification

OWIN defines a standard interface between .NET web servers and web applications. The goal of the OWIN interface is to decouple server and application, encourage the development of simple modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.

In even simpler terms the OWIN specification abstracts Web API from its standard IIS host. OWIN gives us Social providers (Google, Twitter, Facebook etc), and security features (Token based authentication). If your hosting in IIS or anywhere else, OWIN helps abstracts the security layer for you so that you could, in theory, host your API anywhere you like.

The Katana Project plays an important role here in that Microsoft has provided additional plumbing to make it even easier for us software devs to host OWIN-based web applications. This is a more accessible abstraction over OWIN, if you will. The Katana Authentication Middleware (a specialized version of OWIN Middleware) supports Cookie based authentication (replaces forms auth), and token based authentication using third parties like Google, Facebook, Microsoft, and Twitter. Lets look at some rudimentary code examples, creating an empty Web project, and then registering the following Nuget packages:-

  • Microsoft.Owin.Host.SystemWeb (v 2.x)
  • Microsoft ASP.NET Web API 2.1 OWIN

We can begin by defining our OWIN based middleware:

public class TestOWINMiddleware{
    private readonly Func<IDictionary<string, object> Task> _next;

    public TestOWINMiddleware(Func<IDictionary<string, object> Task> next)
    {
		app.UseGoogleAuthentication(new GoogleAuthenticationOptions
        {
			_next = next;
		}

        public async Task Invoke(IDictionary<string, object> env)
        {
			env["server.User"] = CreatePrincipalHere();
			await _next(env);
		}
	}
}

Some important points about the above code, we are about to register the TestOWINMiddeware class above and in doing so we place each object into a Dictionary of Tasks. server.User is one of many dictionary items for storing/retrieving principal info, however, you could also get at principal as follows (OwinContext is just a nice wrapper around the dictionary objects):

var context = new OwinContext(env)
context.Request.User

Lastly we call the next item in the pipeline by calling _next(env), assuming there is nothing left in the pipeline it goes on to call ASP.NET Web API pipeline. We bootstrap OWIN into our pipeline by convention, it involves creating a Startup class with a Configuration method as described below, for you Web Forms guys this is equivalent to Global.asax.cs file that gets called when a Web application starts up.

public class Startup
{
    public void Configuration(IAppBuilder app)
	{
		app.Use(typeof(TestOWINMiddleware));
	}
}

Authentication Filter Attribute

At last we are ready to define an Authentication Filter, that does nothing except for highlight examples of just how you could can gain access to the principal user:

public class AuthenticationFilterAttribute : Attribute, IAuthenticationFilter
{
    public async Task AuthenticationAsync(HttpAuthenticationContext context)
    {
		context.Principal //If we are doing authentication we would set this principal and recover it here.
		context.ActionContext.RequestContext.Principal // To pick up what is in the pipeline we use this
    }

    public async Task ChallengeAsync(HttpAuthenticationContext context)
    { }

	public bool AllowMultiple()
    {
		get { return false; } 
	}
}

I have defined the above class as an Attribute and as IAuthenticationFilter and so you could reasonably place this class over a specific action or apply it to the entire pipeline in App_Start\WebApiConfig.cs.

Summary

Many of us have invested time in supporting our authentication needs in HttpModules and HttpMessageHandlers, and while the underlying infrastructure of IIS is unlikely to change in homogenous Microsoft development shops, the general practices around security are changing, and it would behoove us all to pay attention to the platform agnostic shift Microsoft is encouraging us to pursue.



Comment Section

Comments are closed.