Introduction

The service also provides a socket policy file server which is required for Adobe flash clients to connect (using as3httpclientlib).

A flash client application (WebServiceSubscribe) is also available for download which demonstrates connecting to the web service. Any other client types can of course connect as well.

Background

The reason I want to share this code is because it has taken a very long time to get to this point. There are many tutorials and code snippets out there on the web about creating a restful service in WCF, but none of them cover all the features that one would actually want to utilize in an internet hosted service - there are just bits and pieces here and there. A lot of them also implement features in strange ways, trying to make WCF do things it just doesn't want to do, or shouldn't do.

A lot of the complexity comes down to the configuration - if this is done properly, things work together nice and simple.

So let's get to it!

Using the Code

The most important part to getting your service up and running is the configuration. The configuration provided by the WCF Rest Service Template 4.0 is just not up to the task as it doesn't provide any config for security or authentication. When you actually want these features, your configuration looks a lot different.

bindings.webHttpBinding.binding

security.transport.clientCredentialType - "Basic" means we are using Basic authentication over SSL

behaviors.serviceBehavior.behavior

serviceDebug.includeExceptionDetailsInFaults - only set true if in development

serviceCredentials.userNameAuthentication.userNamePasswordValidationMode - "Custom" means we are implementing our own user/pass validation class - i.e. so we can query a database rather than using Windows based authentication

serviceCredentials.customUserNamePasswordValidatorType - the runtime class where we validate the credentials

serviceAuthorization.principalPermissionMode - "Custom" means we can implement our own authorization policy for role based access to our service methods

serviceAuthorization.authorizationPolicies.add.policyType - This class needs to be implemented so we can associate our own iPrincipal implementation with the running thread, so that we can take control of its "IsUserInRole" method for role based security.

endpointBehaviors.behavior

webHttp.defaultBodyStyle - "Wrapped" means our json result will be contained within a json object i.e. "{}"

webHttp.defaultOutgoingResponseFormat - "Json" means our service serves responses in json rather than XML

webHttp.helpEnabled - "true" means a user can browse to e.g. https://localhost:8000/WtfService/Help and the framework will auto-generate a help page which describes the web service functions

Because we set up everything in the configuration file, instantiating the service is very simple. We just create a new ServiceHost and pass in the type of our service.

The SocketPolicyFileServer is just another service we create to let flash clients connect which serves up a SocketPolicyFile.xml file over TCP port 843. The credit for this socket policy code goes to http://socketpolicyfile.codeplex.com/.

Password Validation

Password validation occurs in a class overriding UserNamePasswordValidator, and is referred to in the config file. This is what it looks like - obviously you would want to query a real database here:

///<summary>/// Here is where we actually validate the password
///</summary>class WtfUserNamePasswordValidator : UserNamePasswordValidator
{
publicoverridevoid Validate(string userName, string password)
{
if (string.IsNullOrEmpty(userName) | string.IsNullOrEmpty(password))
thrownew ArgumentNullException();
//validate the username and password here against the databaseif (userName != "John" | password != "Doe")
// This throws an informative fault to the client.thrownew FaultException("Unknown Username or Incorrect Password");
// When you do not want to throw an informative fault to the client,// throw the following exception.// throw new SecurityTokenException("Unknown Username or Incorrect Password");
}
}

Role Based Authentication

Password validation only authenticates the user. But we also want role based access to our web service methods. The first part of solving this is to create our own implementation of the IPrincipal interface like so:

WCF will call into the Evaluate function, and from there we can get the IIdentity, which will among other things, contain the username of the client making the service call. We then wrap this IIdentity in our custom IPrincipal, and set it to the evaluationContext.Properties["Principal"]. Once this is set, WCF will automatically call the IsUserInRole on any PrincipalPermission attributes that we apply to our service class. More information on this and code can be found here.

The Service Class

Next we will take a look at our service class and see how it all comes together. Note that you do not need to apply the OperationContract attributes to the methods, nor do you need to apply DataContract to complex types passed to or returned from the service (e.g. class Person below).

where certhash is the hash of the certificate you just created, and appid can be a random guid, or you can just pull it out one in your .NET project properties, assembly info.

That should be all you need to get the SSL side of your service running.

To check that everything is working, you should go to your web browser and test it out by browsing to the URL https://localhost:8000/WtfService/HelloWorld/John/Doe (for the credentials use username John, password Doe).

We get the red cross in crome for the https because it is a self-signed cert.

Flash Client (if you won't use flash, you can skip to the end)

Some precursors before using as3httpclientlib with self-signed certificate:

In order to allow a flash client to connect to the service, it should pretty much be out of the box with as3httpclientlib if you use a certificate signed by a real CA. But we are self-signing, so the as3httpclientlib available at https://github.com/gabriel/as3httpclient is not going to work for you.

as3httpclientlib is built on top of as3cryptolib and as3cryptolib by default does not allow self-signed certificates. But browsing the source code for as3cryptolib I found that there is a configuration option in a class TLSConfig that is used in TLSEngine like so:

So we want to set this config.trustSelfSignedCertificates property to true in as3httpclientlib.

So what you can do, is to download the source for as3cryptolib (you will need the source from svn not the download page as that is out of date) and then compile it.

Then download the source for as3httpclientlib, and replace the as3cryptolib .swc file reference with the one you just compiled (the one as3httpclientlib has in its references is out of date, and does not support this config feature). And then make the following amendment to the class HTTPSocket in as3httpclientlib:

Points of Interest

I initially thought of implementing a custom authentication method on top of WCF rather than using SSL so I could avoid the SSL handshake and so save a bit of bandwidth (and also the trouble with getting things working from flash). I pretty much had the whole thing implemented including HMAC, RSA, AES and it was a pretty robust solution.

The problem was I could only encrypt content back from the server to the client, and not from the client to the server. This is due to implementing encryption inside a MessageEncoder in WCF (similar to here), which cannot access the HTTP headers on the ReadMessage side due to the message not being created yet. I realised the only way to do it properly would be to create an entire Transport channel implementation, which would just be getting ridiculous. I could have implemented a handshake and put AES session keys in a static class (which by itself is messy), but then I'm using a handshake, so I may as well use SSL and make things MUCH MUCH simpler. Which is what I did.

Conclusion

I hope this article helps you to get started with REST in WCF. I don't know about the rest of you but I like to get on with the coding of the business logic rather than messing around with the technology implementation, as a huge amount of time can be wasted without achieving anything of value, i.e., now that I have got all this up and running, I still have to develop the functionality of the web service I set out to build in the first place. ;) Hopefully this saves others from wasting their time.

Share

About the Author

Has a background in Finance and Software development.
Has worked as a RAD developer for the likes of Credit-Suisse and Westpac Banking corporation.
Currently self-employed working on some personal projects.

Comments and Discussions

Thank you for your effort! It works beautifully! For those who just commented it does not work, please read through the article, and follow the steps. Jeremylei has made every effort to cover most scenarios.

I accessed to wcf with username/password (Timbake/timbake) instead of John/Doe, then I received the messages as follows:
HTTP Error 401.2 - Unauthorized
You are not authorized to view this page due to invalid authentication headers.

Could it get the account from certificate, not from UserNamePasswordValidator interface?

As an XP user, this sucks. One thing after another. Now it refuses to compile because HTTP could not register URL https:// :8000/WtfService/. Another application has already registered this URL with HTTP.SYS.

This post was very helpful. Though I do have a question. Is it possible to access the username/roles of an authenticated user from inside the service code? I would like to have a service that will return slightly different data depending on what role the user is in.

Thank you! I have spent hours looking for the pieces you have collected. I wish I could say I have it all running. I like your logic at the end especially. I am attempting a simple API based on WCF and need everything you collected. I am new to WCF but a real fan of REST and Flex and Actionscript. This really helps me evaluate the alternatives such as WebOrb, etc.