OWIN Integration Testing with OAuth Bearer Tokens

Situation

The situation is pretty simple. We have a project written with Web API 2.2 that we have running with OWIN. The API requires user authorization. To accomplish that, we use the OWIN OAuth libraries.

Upon until recently, the OAuth authorization server (the thing that takes in the user credentials and issues the token) and the API (the resource server) were hosted in the same site and web project.

Integration testing was pretty easy at this point. For the authorized calls, we simply wrote helper methods that logged a test user in through the authorization server (hosted along with the API in the OWIN test server), got a bearer token and then made the integration test calls.

Problem

When we recently decided to split the authorization server and resource server code up into two separate code bases (so that they could be hosted separately) we ran into issues with the authorization and API calls no longer being possible within a single integration test. The code to generate the bearer token was now no longer accessible in the test server for the API integration tests because the authorization server was now designed to be hosted separately. We’d have to somehow generate the bearer token without making a call with the OWIN test server.

Solution

The solution is to generate a valid bearer token in your test code and send it along with your test API call as you would have previous. How to generate that valid bearer token though?? It turns out to be easier than I thought.

How you use OWIN’s test server is beyond the scope of this blog post, but eventually you’ll have some code resembling this:

var server = TestServer.Create();

You’ll have to use a overload of the Create() method to capture a reference to the server’s IDataProtector. This interface defines what OWIN OAuth will use to encrypt a ClaimsIdentity into a valid bearer token.

Update your server creation code like this:

  var dataProtector;
  var server = TestServer.Create(app =>
  {
    var s = new Startup();
    s.Configuration(app);

    dataProtector = app.CreateDataProtector(
      typeof(OAuthBearerAuthenticationMiddleware).Namespace,
      "Access_Token", "v1");
  });

You have to get the dataProtector this way because it’s the same way that the OWIN OAuth libraries get it before trying to decrypt the bearer token. See the source for the OWIN OAuth code here: OAuthBearerAuthenticationMiddleware.cs

Once you’ve “captured” the dataProtector, in your integration test (or in some helper code, probably) you can generate your ClaimsIdentity and then your bearer token with the dataProtector.

  // inside an integration test
  using (server)
  {
    // create your valid identity any way you need to here
    ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity("username"));

    // these classes are defined in the OWIN OAuth libraries.
    var properties = new AuthenticationProperties();
    var ticket = new AuthenticationTicket(identity, properties);
    var format = new TicketDataFormat(dataProtector);

    string bearerToken = format.Protect(ticket);

    // ... call your API through the test server with the bearer token...
    var response = server.CreateRequest("/api/someendpoint")
        .AddHeader("Authorization", "Bearer " + bearerToken)
        .GetAsync()
        .Result;
  }

Using NuGetPackager 0.5.5 with GitVersionTask 3.4.1

I’m using both NuGetPackager with GitVersionTask on my project that provides EntityFramework persisters for NServiceBus: GoodlyFere.NServiceBus.EntityFramework.

NuGetPackager seems to work seamlessly with GitVersionTask 2.0.0. However, GitVersionTask is up to version 3.4.1 and I just hate sitting at a version that far behind!

So, I updated my NuGet package to the latest version of GitVersionTask. That’s 3.4.1 right now. Too bad, so sad! That caused this error:

The "CreatePackages" task was not given a value for the required parameter "Version".	1

The Problem

The problem turns out that NuGetPackager 0.5.5 is looking for a MSBuild property called “GfvNuGetVersion”. See the code in the .targets file here.

GitVersionTask 3.4.1 (somewhere in a release since 2.0.0) changed that property name to “GitVersion_NuGetVersion”. See the code here.

The Solution

So, how to fix this? NuGetPackager will probably be updated some day, but for now you can just translate the property in your .csproj file before the CreatePackage task is called in NuGetPackager.

Open up your .csproj file directly in some text editor like Notepad++. Find these two lines at the bottom of the file:

<Import Project="..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets"
        Condition="Exists('..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets')" />
<Import Project="..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets"
        Condition="Exists('..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets')" />

Before those two lines, add a target and a property group. The target will create a task that translates the new property to the new property. The property group wil define a BuildDependsOn to call that target before the CreatePackages target is called.

<Target Name="TranslateNugetVersion"
        Condition="'$(Configuration)' == 'Release'">
    <CreateProperty
        Value="$(GitVersion_NuGetVersion)">
        <Output
            TaskParameter="Value"
            PropertyName="GfvNuGetVersion" />
    </CreateProperty>
</Target>
<PropertyGroup>
    <BuildDependsOn>
        $(BuildDependsOn);
        TranslateNugetVersion
    </BuildDependsOn>
</PropertyGroup>
<Import Project="..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets"
        Condition="Exists('..\packages\GitVersionTask.3.4.1\Build\dotnet\GitVersionTask.targets')" />
<Import Project="..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets"
        Condition="Exists('..\packages\NuGetPackager.0.5.5\build\NuGetPackager.targets')" />

Now, when you build your project, everything should work great!

You Can't Subscribe to IEvent with NServiceBus

The reason you might want to subscribe to IEvent is pretty straightforward. I wanted to do it for the simple reason of wanting to be able to choose (based on configuration) whether I wanted to notify anyone of any event that could be published on my bus.

In other words, whenever an event of any type was published, I wanted one particular endpoint to subscribe to that event and then decide whether it should do anything with it.

I thought the code to do that should be pretty simple. Since all published events should implement the IEvent interface and NServiceBus supports polymorphism in its message handling, creating a message handler that implemented IHandleMessages<IEvent> should be all I should have needed!

I was testing this with only partial success and so I thought it was working.

public class EventHandler : IHandleMessages<IEvent>
{
   public void Handle(IEvent message)
   {
     ...
   }
}

My Partial Success

The reason I had partial success was because I was also explicitly handling other events in the same endpoint on a special saga I had setup. So, when the endpoint started up, it would subscribe to these events. At first, I only wanted to send notifications for these events anyway, so it all seemed to be working. My special IEvent would work because the Saga subscribed this same endpoint to those few events explicitly.

My Full Failure

I realized I had only partially succeeded when I started wanting to send notifications for other events that were not in that Saga. I dug into the issue for a few hours and finally began to wonder if NServiceBus (or maybe the RabbitMQ transport) was explicitly ignoring IEvent when it setup subscriptions.

Sure enough, it does.

To build a list of types to subscribe to, NServiceBus uses the Conventions class in the NServiceBus.Core namespace. One of the checks that code does is to filter the list of potential types with the IsEventType method. This method checks if the Type is in a Particular (NServiceBus) DLL. See the code here: IsEventType

My Solution

The solution is simple enough. Instead of listening to IEvent, listen to a custom interface that you implement on all of your events. This is probably more close to what you are trying to do anyway–listen to all events that your system produces.

So, I simply created a marker interface called ICustomEvent.

public interface ICustomEvent : IEvent { }

Then, on all of my bus event classes, instead of implementing IEvent directly, I implemented ICustomEvent.

My handler then looked like this.

public class EventHandler : IHandleMessages<ICustomEvent>
{
   public void Handle(ICustomEvent message)
   {
     ...
   }
}

Now, the right subscriptions are all set up and my single handler gets every single event published by my entire bus.

Adding a RabbitMQ Configuration File When Running as a Windows Service

A little context

I was having a hard time adding a rabbitmq.config file today. I added it in the right location, restarted the RabbitMQ Windows service and the logs still showed that the configuration file was not found.

If you’re experiencing the same problem, you’ll see a similar error message in the RabbitMQ log file after you restart the Windows service.

=INFO REPORT==== <date here>
node			: rabbit@<server>
home dir		: C:\Windows
config file(s)	: c:/path/to/config/rabbitmq.config (not found)
...some other stuff...

This will happen if you just install your RabbitMQ server with the normal, default installation process and then try to add a configuration file later. By default, RabbitMQ doesn’t install configuration file and just uses all it’s defined defaults.

Solution

I read the documentation a little more closely and finally came upon this line: “Windows service users will need to re-install the service after adding or removing a configuration file.”

Oops. Guess I should have read the documentation more closely the first time around! The easiest way to do this is as follows (start a command prompt as administrator):

> cd "C:\Program Files (x86)\RabbitMQ Server\rabbitmq_server-3.6.0\sbin"
> .\rabbitmq-service.bat remove
> .\rabbitmq-service.bat install
> .\rabbitmq-service.bat start

Of course, The path you cd into will depend on the version of RabbitMQ you have installed.

Working with x.509 Certificates in .NET

I found a lot of very helpful details about certificate storage and usage in Windows and .NET in this article.

Particularly, the explanation of where certificates and private keys can be stored for UserStore certificates was very helpful in debugging some issues I’m currently having on a production server.

Paul Stovell’s blog post