Sunday, May 25, 2014

WCF Security: Requiring Authorization to lock down your Exposed Services


WCF Security is definitely not something that can be picked up easily. It isn't plug and play or something that can simply be turned on or off; and it most definitely is not easy to understand or programmer friendly. I have been banging my head against a wall trying to understand WCF Security for a long time now, with many unsuccessful attempts repeatedly. I am stubborn though and keep coming back to it whether I get a black eye or not. However when something becomes necessary to understand - the urgency goes up, it doesn't matter how many times you get a black eye - you figure it out. Sink or swim. In other words I struggled with this topic a lot and I finally figured it out. My first mistake was I was going about the topic all wrong. You need to ask yourself a very important question when you are working on Service Security in general - what are you trying to achieve? Do you want authentication, authorization or both?


To make sure we are all on the same page, you have to make sure you know what the difference is between authentication and authorization.
  • Authorization - giving permission or authority. Are you allowed to be here? Yes, then welcome - No, then hit the road jack, come back when you are given permission.
  • Authentication - confirming the truth of an attribute of a single piece of data or entity. Are you who you say you are? Let's check your username and password. If it checks out, then come on in. If it does not check out, halt - you are not allowed any further!
Once you understand what the difference is between those two aspects, you need to take a step back and realize, that maybe you were looking at the problem incorrectly. Trying to do both at the same time when they are completely different. When I realized that this was my situation I started phrasing my google searches differently because googling for "WCF Security" gives you tremendously different results from "WCF Authorization". 

Inevitably you will see the term "Security Certificate" - don't worry we don't need that here - although it is important and recommended that you use SSL when you can. On your own this is more difficult to deal with because you need to, assuming you are using IIS, setup IIS properly to use your certificate - this alone impacts which WCF Endpoint Bindings you can use. For example BasicHttp (HTTP) vs. WSHttp (HTTPS).

After discovering all of this I realized I needed to implement Authorization into my WCF Service, it made perfect sense for my needs. My scenario is simple: I have internal Web Services (WS) that need to talk to each other - no third parties involved here. If you need to deal with third parties, then this solution is going to be too rigid, however with some creativity you can make this work for you.

Let's work with Authorization


This may be a bit much to take in at first, but just keep an open mind and read carefully and try your best to understand along the way. There are several steps involved with getting Authorization to work and this requires cooperation from the client and from the server (which is why working with third parties would be difficult). Those steps are:
  1. Build your Custom Message Header - these message headers are NOT to be confused with Http Headers, they are specifically SOAP message headers when using the basicHttpBinding or wsHttpBinding. This introduces a problem that I will explain below.
  2. Build your Message Inspectors
    1. Dispatch Message Inspector: IDispatchMessageInspector
    2. Client Message Inspector: IClientMessageInspector
  3. Build your Custom Behavior
    1. Behavior Attribute itself - wcf endpoint behavior definition
    2. Behavior Extension Element - required for app/web config, let's assume web.config moving forward
  4. Modify your server side web.config
  5. Modify your client side web.config
This may seem like a lot of steps, but really it isn't. The good news is that once you implement the code the first time, all you have to do in the future is modify your configs - which is pretty simple as well. I strongly recommend putting all of this code into a single project. This project will be referenced by both the server and client sides. That way you are 100% ensured uniformity, especially if you have to modify the code - there is absolutely no reason to implement this code more than once.

Build your Custom Message Header

As mentioned earlier these message headers are message headers which are not to be confused with Http Headers - they are not the same! The message header we have in question here is what will actually carry the authorization arguments over to the server from the client. The client will inspect the outgoing message before it is sent and inject this Message Header into the message. The server will inspect each incoming message for 4 parts:
  1. Header Name - the name of the message header
  2. Header Namespace - the namespace of the message header
  3. Token Name - the name of our authorization node
  4. Token Value - the value of the authorization node
The actual Custom Message Header is a class you have to write and this class must inherit from the MessageHeader class. I have named my class AuthorizationHeader. You have to override a few elements as demonstrated in the code. The most important thing to keep in mind here is serializing the message contents in the OnWriteHeaderContents(...) method. For my design I made the the header name, header namespace, token name and token value all dynamic. I did this for two reasons: 
  1. I did not want to hardcode any strings into this class so it will remain fully configurable from the web.config
  2. Just in case the values of the aforementioned properties became compromised, they could be changed immediately without having to recompile anything
I am extra paranoid about people getting values through packet sniffers and other means, so I figured instead of making the header properties and values human readable why not make them all resemble passwords? Here is an example of a Message Header:

Example of a SOAP message's message headers section containing a custom message header
Please note that the Token Name and Value are properties I came up with - this is not required and it can be named anything else, but for my design I called it a Token. This token is the contents of the message. More contents could have been added, but since this has to be checked twice and for every message, keeping it small is better.

Code: AuthorizationHeader.cs

Build your Message Inspectors

The hardest part was building the Custom Message Header. Believe it or not this part is very easy. Your message inspectors are what are going to:
  1. Inject the authorization Header into each outgoing message. This is done by the Client message inspector using the "BeforeSendRequest(...)" method.
  2. Inspect each incoming message to make sure it contains an Authorization Header with the 4 appropriate aforementioned values. This is done by the Dispatch (Server) message inspector using the "AfterReceivedRequest(...)" method. If those values exist then the requester is Authenticated, if those values do not exist or do not match, then the requester is not authenticated and they will be issued an UnauthorizedAccessException.
Example of an end to end transaction involving a message inspector
In the above example we are assuming that there is a web method in this WCF Service (I am calling it the AwesomeService) that will add numbers via the "AddNumbers(...)" method. However we don't want to let anyone add numbers, only consumers with the proper Authorization are allowed to do this.

For the following three sections I recommend looking at the code while reading along:

Dispatch Message Inspector

The Dispatch Message Inspector can inspect messages after arrival (AfterReceiveRequest(...)) and before sending a response (BeforeSendReply(...)). For my implementation purposes I only defined the "AfterReceiveRequest" method, as that is all I required at the moment. The general idea for this method is simple and can be described in the following questions:

  1. Is the expected Authorization Header present?
  2. Can the header be deserialized from XML into an AuthorizationHeader object?
  3. Does the Authorization Token match what the server is expecting?

Message Inspectors and REST

One of the problems I ran into here was that I was trying to satisfy REST calls and SOAP calls. This was very tricky and at that point it was very clear why WCF is not the greatest platform for REST. The message inspector and header messages are geared towards usage with non webHttpBinding. In other words - how do you append a header messages in a REST call? Let me be clear - I am not talking about http headers, I am talking about Message Headers. In the context of the basicHttpBinding or wsHttpBinding it would be a SOAP header. You can't use the Client Message Inspector for REST, as it is only triggered in a server side context, for bindings other than webHttpBinding it seems.

Therefore in order to combat this problem, I came up with a not so wonderful way of handling it. I cannot condone what I did, but it works. However once again, I won't say this is the right way to do it - it is just a work around. In order to get this to work with REST I had to use the Query String in an unsavoury manor. I came up with a arbitrary scheme for passing the AuthorizationHeader information over to the message inspector and it looks like this:

So basically the scheme I made up is: ?AuthorizationHeaderName=AuthorizationHeaderNameSpace&AuthorizationToken=AuthorizationTokenValue

This is picked up by the message inspector first, if it is present then it is evaluated, if not then the SOAP headers are inspected following the same rules as usual.

Client Message Inspector

The Client Message Inspector can inspect messages before sending a request (BeforeSendRequest(...)) and after receiving a reply (AfterReceiveReply(...)). For my implementation purposes I only defined the "BeforeSendRequest" method, as that is all I required at the moment. The general idea here is very straight forward and obvious:

  1. Create a new AuthorizationHeader with the appropriate AuthorizationTokenValue
  2. Add this AuthorizationHeader to the current request's Headers collection
There isn't much more to the client message inspector than that.

Build your Custom Behavior

This is a more interesting step to implement - even though it is literally a copy/paste step, you are actually creating an avenue for implementing your Message Inspector via the web.config. This is done by defining a behavior which can be implemented by your WCF Service. This behavior is required by both the server side and client side because this is what causes the message inspection to actually happen, hence it being a behavior. Your client and server will behave according to the Message Inspector definitions set for each inspector respectively.

Behavior Attribute

The Behavior Attribute implements the IEndpointBehavior interface which has four methods, but we are only interested in two of the four:
  • ApplyClientBehavior - use the client message inspector logic (BeforeSendRequest)
  • ApplyDispatchBehavior - use the dispatch message inspector logic (AfterReceiveRequest)
These behaviors are triggered depending on where they are registered. There are examples below, but before we get to the examples there is just one more piece to this puzzle and that is one more copy/paste step which is the Behavior Extension Element.

Behavior Extension Element

This class is literally just a necessity in order to expose the Custom Behavior. This will make more sense once we go to the web.config to review the changes required in the web.config. The behavior extension element is utilized in the "extensions" node: <system.serviceModel><extensions /></ system.serviceModel>.

Server Side Web.Config (Dispatch Message Inspector)

Here is a server side (Dispatch Message Inspector) web.config example that should tie everything together nicely for you and give you more clarity. It is a large screenshot because one of the arguments cannot be broken up on multiple lines.

Click on the image to expand it. Cross reference it with the code and understand what is happening here.
Basically what is happening here is that the Behavior Extension Element is the gateway to leveraging the Message Inspector code. Starting from the top you can see that Behavior Extension Element must be defined explicitly for use in the web.config. You are defining a new XML node named "authorizationBehavior" in the behaviorExtensions section. The class that this node will use to operate is the AuthorizationBehaviorExtensionElement class. This class points to the AuthorizationBehavior class. This class points to the AuthorizationMessageInspector class. In this context, since it is for the Services section of the web.config, it will use the Dispatch Message Inspector method: "AfterReceiveRequest".

Client Side Web.Config (Client Message Inspector)

This is the client side web.config example and it isn't different from the server side example except for the obvious fact that the context is for the client and not the server. Therefore the only change in the story is that the Dispatch Message Inspector method that will be used is the "BeforeSendRequest" method.

Click on the image to expand it

App.Config/Web.Config - Configuration

Config Examples: Web.Config/App.Config

The provided configuration file is for reference only - it purposely excludes the binding section because that really doesn't matter for this article. The config is broken up into three parts:
  1. Application Settings
  2. Server Side Settings
  3. Client Side Settings
Here are a few suggestions for when you are configuring your Web.Config and App.Config. If you already have a massive config file, I suggest taking a look at this link. Consider taking different config sections and breaking them down into external files. It makes life a lot easier to navigate your main config and to even deploy changes. You can work on an individual file as opposed to working on your main config and making it grow ridiculously large.

When you are describing the "WCFServiceSecurity" dll in the web.config (or your own copy of this dll - feel free to change it however you want) you need to keep in mind that if you make any mistakes or put any line breaks in the "type" attribute - your service will fail during runtime. Also make sure the dll is present - as stupid as that sounds, that is usually the problem aside from mal configuration.

type="WCFServicesSecurity.AuthorizationBehaviorExtensionElement, WCFServicesSecurity, Version=, Culture=neutral, PublicKeyToken=null" />

name="[Name of the Endpoint Behavior Node]" 
type="[DLL Name].[Name of Behavior Extension Element Class], [DLL Name], Version=, Culture=neutral, PublicKeyToken=null" />

The way I designed this assembly is to use shared keys for the client and the server. If the keys aren't the same for both - then the client will not be authorized. So basically make sure those keys are in sync.

If for whatever reason you need to disable Authorization, just remove the "behaviorConfiguration" attribute from your bindings.

Credit and Sources

I got 95% of my information and source code from the following articles written by Paolo Pialorsi. His articles are very well written. I just happened to take two of his articles and slap them together to make one solid solution for myself. This stuff is slightly complicated, but once you get it - you get it.
The rest of my information came from MSDN white pages and StackOverflow - which really just all led me to Paolo's articles.

No comments:

Post a Comment