Damian Hickey

Mostly software and .NET related. Mostly.

Protecting a Self-Hosted Nancy API with Microsoft.Owin.Security.ActiveDirectory

This post is the Nancy version of Vittorio's 'Protecting a Self-Hosted API with Microsoft.Owin.Security.ActiveDirectory'. Since I'm lazy, I may even be lifting some parts of it verbatim, if you don't mind, Vittorrio ;)

I'm going to skip the intro to Owin etc, if you are reading this, you probably know all about it by now. (Except for you Phillip; Get yout s**t together man!). This tutorial will be using Nancy.MSOwinSecurity that I introduced in the previous post.

What I am going to show you is how you can set up a super simple Nancy HTTP API in a console app and how you can easily secure it with Windows Azure AD with the exact same code you use when programming against IIS Express/full IIS.

Here's what we are going to do:

  • Create a minimal self-hosted Nancy Http API in a console app.
  • Add middleware for validating JWT tokens from AAD.
  • Create a console app client to poke our API and challenge the user for credentials.

Create a Minimal Self-Hosted Nancy Http API

Let's start by creating blank solution. I'm a bit unimaginative so I am calling this 'NancyAAD'. Note: this entire solution will be targeting .NET 4.5. .NET 4.0 is not supported. Next, we add a console application, 'NancyAAD.Server', that is going to host our Nancy HTTP API. To this project, we're going to add a number of nuget packages, in this order:

  1. Nancy.Owin - This will bring in Nancy and the adapter that allows Nancy to be hosted in an OWIN pipeline.
  2. Microsoft.Owin.Hosting - Provides default infrastructure types for hosting and running OWIN-based applications. There are other hosting implementations out there, if you feel the need to explore.
  3. Microsoft.Owin.Host.HttpListener - OWIN server built on the .NET Framework's HttpListener class.
  4. Microsoft.Owin.Security.ActiveDirectory - The middleware through which we will secure our Nancy HTTP API. This package will pull in a bunch of other packages. We'll be using this later.
  5. Nancy.MSOwinSecurity - This will provide integration between Nancy's context and modules and Microsoft.Owin.Security.*.

Your NancyAAD.Server packages.config should look similar to this:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Owin" version="2.0.2" targetFramework="net45" />
  <package id="Microsoft.Owin.Host.HttpListener" version="2.0.2" targetFramework="net45" />
  <package id="Microsoft.Owin.Hosting" version="2.0.2" targetFramework="net45" />
  <package id="Microsoft.Owin.Security" version="2.0.2" targetFramework="net45" />
  <package id="Microsoft.Owin.Security.ActiveDirectory" version="2.0.2" targetFramework="net45" />
  <package id="Microsoft.Owin.Security.Jwt" version="2.0.2" targetFramework="net45" />
  <package id="Microsoft.Owin.Security.OAuth" version="2.0.2" targetFramework="net45" />
  <package id="Nancy" version="0.21.1" targetFramework="net45" />
  <package id="Nancy.MSOwinSecurity" version="1.0.0" targetFramework="net45" />
  <package id="Nancy.Owin" version="0.21.1" targetFramework="net45" />
  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
  <package id="Owin" version="1.0" targetFramework="net45" />
  <package id="System.IdentityModel.Tokens.Jwt" version="1.0.0" targetFramework="net45" />
</packages>

Next we'll define our Nancy module and a very simple GET endpoint that we'll want to secure later:

namespace NancyAAD.Server
{
    using Nancy;

    public class ValuesModule : NancyModule
    {
        public ValuesModule()
        {
            Get["/values"] = _ => new[] { "value1", "value2" };
        }
    }
}

That done, let's add the Startup class for hosting our Nancy application in OWIN:

namespace NancyAAD.Server
{
    using Owin;

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseNancy();
        }
    }
}

This says that Nancy is handling all requests from the root. Nice and simple. 

Lastly, we need to host the OWIN application itself. In Program.cs, we write the following:

namespace NancyAAD.Server
{
    using System;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using Microsoft.Owin.Hosting;

    internal class Program
    {
        public static void Main(string[] args)
        {
            using (WebApp.Start<Startup>("http://localhost:9000/"))
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.WriteLine("Nancy listening at http://localhost:9000/");

                // Test call
                var client = new HttpClient();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                var response = client.GetAsync("http://localhost:9000/values").Result;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(response.Content.ReadAsStringAsync().Result);

                Console.ReadLine();
            }
        }
    }
}

The call to WebApp.Start initializes a new server, which listens at the specified address. The rest of the method calls the Nancy HTTP API to double check that we did everything correctly.

There is one subtle difference here compared to Vittorio's post - we are defining an Accept header "application/json". The reason is that because Nancy supports view engines where it's default behaviour when returning a model for a request with no accept header, is to try to resolve a view. This would result in an exception for us as we haven't defined any views.

F5'ing the app should result in:

Exactly the same as Vittorio's screen shot. Nice.

Before moving on to the next task, remove the test call from the Main method and change it to the following:

public static void Main(string[] args)
{
	using (WebApp.Start<Startup>("http://localhost:9000/"))
	{
		Console.ForegroundColor = ConsoleColor.Blue;
		Console.WriteLine("Nancy listening at http://localhost:9000/");
		Console.WriteLine("Press ENTER to terminate");
		Console.ReadLine(); 
	}
}

Secure the Nancy HTTP API with Windows Azure AD

Here comes the raison d’être of the entire post. We have already added the Microsoft.Owin.Security.ActiveDirectory nuget package, now let's add it in the right place into the OWIN pipeline. Note, the order things are defined in the pipeline are important, so we must add this before Nancy so requests are piped through it before hitting the Nancy handlers. 

Our OWIN pipeline with the middleware added now looks like:

public void Configuration(IAppBuilder app)
{
	app.UseWindowsAzureActiveDirectoryBearerAuthentication(
		    new WindowsAzureActiveDirectoryBearerAuthenticationOptions
		    {
		        Audience = "https://contoso7.onmicrosoft.com/RichAPI",
		        Tenant = "contoso7.onmicrosoft.com"
		    })
	      .UseNancy();
}

The new code is the "UserWindowsAzure....". You’ll notice that instead of relying on app.config settings, values are passed directly to the middleware. This is another beauty of OWIN, you can now use can keep such settings wherever you deem most appropriate.

Now our pipeline includes the right middleware: if we receive a JWT, we’ll validate it and if it checks out we’ll pass the corresponding ClaimsPrincipal to the handler delegate. Very good, but not good enough. Let’s modify the module class to mandate that all callers must present a valid token from the tenant of choice: 

public class ValuesModule : NancyModule
{
	public ValuesModule()
	{
		this.RequiresMSOwinAuthentication();
		Get["/values"] = _ =>
		{
			ClaimsPrincipal claimsPrincipal = Context.GetMSOwinUser();
			Console.WriteLine("==>I have been called by {0}", claimsPrincipal.FindFirst(ClaimTypes.Upn));
			return new[] {"value1", "value2"};
		};
	}
}

The key statement here is "this.RequiresMSOwinAuthentication" - this ensures that a request hitting this module must have a valid authenticated user, otherwise an unauthorized HTTP status code is returned.

The second key statement, "Context.GetAuthenticationManager().User", retrieves the user from IAuthenticationManager where we write a claim to the console, just for demonstration purposes. The UPN claim is among the ones that Windows Azure AD sends in JWTs.

Believe it or not, that’s all we had to do to secure the Nancy HTTP API: we just had to add the code in bold :)

Create a Client App and Test the Nancy HTTP API

Add a new console app project called NancyAAD.Client (see, I'm not really imaginative!). To this project, install the 'Microsoft.WindowsAzure.ActiveDirectory.Authentication' nuget package. This package contains the main assembly for the Windows Azure Authentication Library (AAL) and provides easy to use authentication functionality for .NET client apps. Your packages.config should look like;

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.WindowsAzure.ActiveDirectory.Authentication" version="0.7.0" targetFramework="net45" />
</packages>

Next up, the Main method should looks like this:

namespace NancyAAD.Client
{
    using System;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using Microsoft.WindowsAzure.ActiveDirectory.Authentication;

    internal class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Client ready.");
            Console.WriteLine("Press any key to invoke the service");
            Console.WriteLine("Press ESC to terminate");
            ConsoleKeyInfo consoleKeyInfo;

            var authenticationContext = new AuthenticationContext("https://login.windows.net/contoso7.onmicrosoft.com");

            do
            {
                consoleKeyInfo = Console.ReadKey(true);
                // get the access token
                AuthenticationResult authenticationResult = authenticationContext.AcquireToken(
                    "https://contoso7.onmicrosoft.com/RichAPI",
                    "be182811-9d0b-45b2-9ffa-52ede2a12230",
                    "http://whatevah");
                // invoke the Nancy API
                var httpClient = new HttpClient();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
                HttpResponseMessage response = httpClient.GetAsync("http://localhost:9000/values").Result;
                // display the result
                if (response.IsSuccessStatusCode)
                {
                    string result = response.Content.ReadAsStringAsync().Result;
                    Console.WriteLine("==> Successfully invoked the service");
                    Console.WriteLine(result);
                }
            } while (consoleKeyInfo.Key != ConsoleKey.Escape);
        }
    }
}

This is a very classic ADAL client and is virtually identical to the one in Vittorio's post. It simply acquires the token, attaches it to the Authorization header before making the call. The one difference is the Accept header is defined, as explained previously.

Starting both projects and triggering a call from the client should result in:

Sign in as any user in your tenant, and you’ll get to something like the screen below:

Ta-dah!

Now go forth and secure your enteprise(!) Nancy Apps!

Full code for this is up on Github

RavenDB and OWIN Webinar

Yesterday I did a webinar for RavenDB 3's Mystery Feature #2 - OWIN support. I'd like to thank Oren, Daniel and the HR team for giving me the opportunity to work on this. 

If you notice any typos, or things aren't as smooth as they should be, it's because it was my first webinar and I only starting preparing 45 mins before hand.

( It's tough to listen to my own voice :s )

Testing Nancy with Owin.Testing

I always like a challenge :)

Nancy has a very nice way of testing, including a mechanism to configure the application as required for each test (swap in a mock etc). It does this with the Browser class:

[Fact]
public void NancyTest()
{
	// Arrange
	var browser = new Browser(with => with.Module<ConfigBootTestModule>());

	// Act
	BrowserResponse response = browser.Get("/config");

	// Assert
	Assert.Equal("Hello configured fellow", response.Body.AsString());
}

(The 'with => ' lambda here is altering the configurable boostrapper)

If you are hosting Nancy with OWIN, and you are using other middleware, you may prefer to test with Owin.Testing for broader test scope. I should state that Owin.Testing was indeed inspired by Nancy.Testing in the first place - I wanted to do the same type of testing with my OWIN application that was possible with Nancy.

So first let's create our OWIN startup class. Here, we are injecting the INancyBootstrapper which will allow us to supply a configurable one in a test:

private class Startup
{
	private readonly INancyBootstrapper _nancyBootstrapper;

	public Startup(INancyBootstrapper nancyBootstrapper)
	{
		_nancyBootstrapper = nancyBootstrapper;
	}

	public void Configuration(IAppBuilder builder)
	{
		builder.UseNancy(_nancyBootstrapper);
	}
}

We're going to add a helper method to configure the bootstraper, to make our test read more like the Nancy Browser example above:

private static HttpClient CreateHttpClient(Action<ConfigurableBootstrapper.ConfigurableBootstrapperConfigurator> configureBootstrapperAction)
{
	return OwinTestServer.Create(builder => 
		new Startup(new ConfigurableBootstrapper(configureBootstrapperAction)).Configuration(builder))
		.CreateHttpClient();
}

Here we are creating our test server, configuring the boostrapper via supplied action and returning an HttpClient.

And the Owin.Testing equivalent test:

public async Task OwinTest()
{
	// Arrange
	var httpClient = CreateHttpClient(with => with.Module<ConfigBootTestModule>());

	// Act
	var response = await httpClient.GetAsync("http://localhost/config");
	var body = await response.Content.ReadAsStringAsync();

	// Assert
	Assert.Equal("Hello configured fellow", body);
}

Looks familiar, doesn't it? ;)

Full gist.

Introducing Owin.Testing

Owin.Testing is discontinued. Use Microsoft.Owin.Testing instead.

Continuing in my mini-series of introductions, Owin.Testing (nuget, github) is an OSS helper library to host your OWIN application and, by using Owin.HttpMessageHandler, make in-memory testing of OWIN applications simple, fast, and environment dependency free. The method by which your application is invoked is using an HttpClient - a similar mechansim from which your users will be interacting with your application. Cookies support is supported by default (and can be turned off).

An example best demonstrates how this works:

//Arrange
OwinTestServer owinTestServer = OwinTestServer.Create(builder => new Startup().Configuration(builder));
HttpClient httpClient = owinTestServer.CreateHttpClient();

//Act
HttpResponseMessage response = await httpClient.GetAsync("http://localhost");

//Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
  1. Line #1 is how we create the test server. The Startup class is the class that defines your OWIN application.
  2. Line #2 is how we create the HttpClient that is internally configured to invoke your OWIN app's root application delegate.
  3. Line #3 & #4 is how we invoke and assert our application. (The assertion here uses the excellent FluentAssertions library).

And that's it! Fast, in-memory, CI friendly OWIN testing :)

A note on Owin.Testing history - I originally started this based of code from Gate. Later, Microsoft.Owin.Testing appeared which is similar, but has since been delisted. I have used some of the code from that. As far as I know at this point, there are no plans to revive Microsoft.Owin.Testing. So for the time being, I'll be continuing to maintain this.

Introducing Owin.SiteMapping

Owin.SiteMapping (nuget, github) is an OWIN middleware analgous to IIS's site mapping. That is, it allows you to partition your OWIN app according to host header, http scheme and port number.

Sometimes an example is best:

public class Startup
{
  public void Configuration(IAppBuilder builder)
  {
    builder
      .MapSite(new SiteMap("www.example.com"), main => main.Use(...))
      .MapSite(new SiteMap("admin.example.com", HttpScheme.Https, 443), admin => admin.Use(...));
  }
}

Here, all requests with host header 'www.example.com', regardless of http scheme or port will be routed down the 'main' OWIN branch. Whereas all requests for 'admin.example.com', only on Https and port 443, will be routed down the admin branch.

 

Bug reports, suggestions and contributions welcome.

Introducing Owin.EmbeddedResources

Update: this post is out of date. The core functionality has been imported into  Microsoft.Owin.StaticFiles. I've de-listed the Owin.EmbeddedResources package.

This library contains an implementation of IFileSystem which is a file system abstraction used by Microsoft.Owin.StaticFiles - a OWIN middleware for serving static content, directory browsing etc. (It isn't available on nuget.org yet, pending security review. It can be obtained from katana CI feed for now).

How to use.

1. Embed your static content as a resource: 

2a. In your OWIN Startup class, specify the IFileSystem implementation, EmbeddedResourceFileSystem:

public class Startup
{
  public void Configuration(IAppBuilder builder)
  {
    builder.UseStaticFiles(config => config.WithFileSystem(new EmbeddedResourceFileSystem())));
  }
}

This will default to using the calling assembly as the source of the embedded content.

2b. If your resources are in a different assembly you can specify the assembly in the EmbeddedResourceFileSystem constuctor:

public class Startup
{
  public void Configuration(IAppBuilder builder)
  {
    builder.UseStaticFiles(config => config.WithFileSystem(new EmbeddedResourceFileSystem(typeof(Foo).Assembly)));
  }
}

The Static files middleware has full support for generating etags and response content types based on extensions.

Notes

Embedded resources lose their folder structure when compiled in. For instance, embedding Resources\Area\Foo.bar will become Resources.Area.Foo.Bar, and embedding Resources\Area.Foo.Bar will also become Resources.Area.Foo.Bar. (Trying to do this with two files won't compile). Due to this non-transitive nature, it is not possible infer the directory from whence an embedded resource originally came from. Thus, directory browsing is not supported in this IFileSystem implementation.

Owin.HttpMessageHandler is now portable

As of version 0.3, Owin.HttpMessageHandler (nuget.org, github) is now shipped as portable class library supporting .NET 4.0 and later, Silverlight 4.0 and later, Windows 8.0 and WindowsPhone 7.1. The ability to customize the owin environment before and after handling the request has been added as well as better support for http 1.1 that requires a host header.

Testing your OWIN application

One of the great things about OWIN is the ability to write tests without having any environmental dependencies (i.e. IIS)  or complicated setup with sperate AppDomains (System.Web.Hosting.ApplicationHost).

Given the following contrived OWIN Startup class that returns OK to all requests...

public class Startup
{
	public void Configuration(IAppBuilder appBuilder)
	{
		appBuilder.UseHandler((request, response) =>
			{
				response.StatusCode = 200;
				response.ReasonPhrase = "OK";
			});
	}
}

('UseHandler' is from the Owin.Extensions package which provides a typed wrapper of convenience around the environment dictionary.)

How do we test this?

First add a package reference to Microsoft.Owin.Testing. As of writing it's prerelease, so don't forget the -pre flag.

Then simply create a TestServer to host your OWIN app, and using the supplied HttpClient, invoke a request like you would against any other web site:

[Fact]
public async Task Should_get_OK()
{
	TestServer testServer = TestServer.Create(appBuilder => new Startup().Configuration(appBuilder));
	HttpResponseMessage response = await testServer.HttpClient.GetAsync("/");
	Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}

How sweet is that!

Now you can write simple, fast, in-memory, multiple-web-framework acceptence tests. This, to me, is one of the killer features of OWIN.

Browse sample project on github.

Owin HttpMessageHandler

Your typical web service call to an OWIN based application goes through the following path:

The purpose of OwinHttpMessageHandler is to allow you to do this:

This is useful for:

  1. End-to-end testing where you don't want to hit the network stack for performance or build server reasons.
  2. Testing your owin middleware or owin compatible framework.
  3. Invoking web service http endpoints or issuing requests against web applications in embedded scenarios through a common pipeline.

Feeback welcome, as always.

Running RavenDB with OWIN and Katana

Just completed this spike and I'm happy with the outcome. Will post solution to Github soon.

Edit: Code available.