Secure RESTful Web Service by WCF Web API, No HTTPS, Seriously?

What if you want to build a secure RESTful web service without using HTTPS? Simple, you just need to implement your secure way to transfer data from endpoints to endpoints. This article written by @Jeff Atwood can definitely give you some hints on how to ensure your message transfer safe. So I will not explain it in the post and suppose you have the basic knowledge of cryptography.

RESTful Web Service

WCF Web API is really handy to build a RESTful web service. Your service class looks as simple as following

[ServiceContract]
public class PlayerResource
{
    private readonly IPlayerRepository _playerRepository;

    public PlayerResource(IPlayerRepository playerRepository)
    {
        _playerRepository = playerRepository;
    }

    [WebInvoke(Method = "POST", UriTemplate = "Create")]
    public Player CreatePlayer(Player player)
    {
        return _playerRepository.Save(player);
    }
}

And with a little bit configuring in your global.asax file

public class MvcApplication : HttpApplication
{
    protected void Application_Start()
    {
        RouteTable.Routes.MapServiceRoute("api/players");
    }
}

And your RESTful web service is ready for up and running.

Secure RESTful Web Service

In order to make sure the incoming and outgoing messages are safe. I will first introduce Message and EncryptedMessage and a helper class EncryptionHelper to encrypt and decrypt the messages.

public class Message
{
    public string AppId { get; set; }

    public string Data { get; set; }

    public string Id { get; set; }

    public string TimeStamp { get; set; }

    public byte[] GenerateFingerprint();

    public bool ValidateHash(byte[] fingerprint);
}
public class EncryptedMessage
{
    public string AppId { get; set; }

    public byte[] Fingerprint { get; set; }

    ///<summary>
    /// The 3DES key used to encrypt/decrypt the message 
    /// </summary>
    public byte[] Key { get; set; }

    ///<summary>
    /// Encrypted message
    /// </summary>
    public byte[] Message { get; set; }
}
public interface IEncryptionHelper
{
    EncryptedMessage Encrypt(Message message);

    Message Decrypt(EncryptedMessage encryptedMessage);
}

Then, we need to change our service class a little bit to support secure data transfer.

[ServiceContract]
public class PlayerResource
{
    private readonly IPlayerRepository _repository;
    private readonly IEncryptionHelper _helper;

    public PlayerResource(IPlayerRepository repository, IEncryptionHelper helper)
    {
        _repository = repository;
        _helper = helper;
    }

    [WebInvoke(Method = "POST", UriTemplate = "Create")]
    public EncryptedMessage CreatePlayer(EncryptedMessage encryptedMessage)
    {
        Message message = _helper.Decrypt(encryptedMessage);

        Player player = Json.Decode(message.Data);

        player = _repository.Save(player);

        message = new Message
        {
            AppId = "Our App Id",
            Id = Guid.NewGuid().ToString(),
            Data = Json.Encode(player),
            TimeStamp = DateTime.UtcNow.ToString()
        }

        return _helper.Encrypt(message);
    }
}

Now, your messages are secured.

Message Handler

Maybe you have noticed that passing in and out encrypted message is not comfy at all. Can we keep the same simplicity of the service function before introduce secure implementation?

Well, the answer is positive. WCF encourage you to implement cross-cutting function (aka AOP) through a couple of handlers (message handler, operation handler). What we need to do is roll out our own message handler to encrypt and decrypt incoming and outgoing messages. So what we need to do is to pass encrypt/decrypt actions to a message handler. The implementation looks as follows,

public class SecuredMessageHandler : DelegatingChannel
{
    private readonly IEncryptionHelper _encryptionHelper;

    public SecuredMessageHandler(HttpMessageChannel innerChannel,
                                 IEncryptionHelper encryptionHelper)
        : base(innerChannel)
    {
        _encryptionHelper = encryptionHelper;
    }

    protected override Task SendAsync(HttpRequestMessage request,
                                      CancellationToken cancellationToken)
    {
        request = DecryptMessageIfTheMessageIsSecuredMessage(request);

        return base.SendAsync(request, cancellationToken)
            .ContinueWith(task =>
                {
                    HttpResponseMessage response = task.Result;

                    response = EncryptMessageIfTheMessageIsSecuredMessage(response);

                    return response;
                });
    }

    private HttpResponseMessage EncryptMessageIfTheMessageIsSecuredMessage(HttpResponseMessage response)
    {
        string data = response.Content.ReadAsString();

        var message = new Message
                          {
                              AppId = "Our App Id",
                              Id = Guid.NewGuid().ToString(),
                              Data = data,
                              TimeStamp = DateTime.UtcNow.ToString()
                          };

        EncryptedMessage encryptedMessage = _encryptionHelper.Encrypt(message);

        var content = new StringContent(Json.Encode(encryptedMessage), Encoding.UTF8,
                                        response.Content.Headers.ContentType.MediaType);

        response.Content.Dispose();

        response.Content = content;

        response.Headers.Add(XMessageType, XMessageTypeSecured);

        return response;
    }

    private HttpRequestMessage DecryptMessageIfTheMessageIsSecuredMessage(HttpRequestMessage request)
    {
        var encryptedMessage = request.Content.ReadAs();

        Message message = _encryptionHelper.Decrypt(encryptedMessage);

        var content = new StringContent(message.Data, Encoding.UTF8,
                                        request.Content.Headers.ContentType.MediaType);
                                        
        request.Content.Dispose();

        request.Content = content;

        return request;
    }
}

And your service function is as simple as it was at first.

    [WebInvoke(Method = "POST", UriTemplate = "Create")]
    public Player CreatePlayer(Player player)
    {
        return _playerRepository.Save(player);
    }
Advertisements

Parameterised Unit Tests

My resent project is using NUnit (a xUnit framework under .NET implementation) to do unit testing. And today, my colleague gave a brilliant suggestion on using NUnit to increase code coverage with Parameterised Unit Tests technique. Here’s the quote from his email.

TestCase attribute can be used to test multiple scenarios, or different code paths.

The following test method will result in four unit tests with four different input… increasing code coverage.

        [TestCase("anything")]  // search with keyword
        [TestCase("")]          // search with empty string
        [TestCase(null)]        // search with null
        public void Search_should_return_pagedList(string keyword)
        {
            // Action
            var result = _searchService.Search<SolrOrganisation>(keyword);

            // Assert
            Assert.AreEqual(2, result.ToList().Count);
        }

Suffering from Visual Studio Crashing with Git?

Hopefully you might get some remedy from this post.

So, how did the story start?

A colleague of mine has symptom several weeks after we began to use Git as our source control tool.

Is anyone else having crash issues with Visual Studio whenever you do a Pull? I’m having it hang for up to 10minutes…..most times resulting in a crash.

Of course there were following discussion on the solution. But, no one worked well so far.

And my turn finally came. My Visual Studio went nuts again this morning. And I decided to look into the problem and finally found something interesting.

Firstly, devenv.exe process kept bashing stuff under $repository\.git\objects folder which contained

>= 1000 files
>= 200 sub folders.

clip_image002



continuing…

500,000 more times…

Solution

Did a little bit search, and run across this article http://gitfu.wordpress.com/2008/04/02/git-gc-cleaning-up-after-yourself/

Ran git gc in git bash

clip_image004

Then here’s the result.

clip_image006

And this solved problem significantly. I believe my colleague owes me some kind of medal.

Configuring Gmail with Redmine

I had been hanging out with Redmine 1.2.0 for a while. Finally, I managed to integrate Gmail SMTP with Redmine.

I used BitNami’s Redmine installer to setup Redmine environment. With installer’s guide, you can configure SMTP server. Once you finished, you will see information as follows in the email.yml file under redmine/config folder.

production:
  delivery_method: :smtp
  smtp_settings:
    address: smtp.gmail.com
    port: 587
    domain: smtp.gmail.com
    authentication: :login
    user_name: [username]@gmail.com
    password: [password]

development:
  delivery_method: :smtp
  smtp_settings:
    address: smtp.gmail.com
    port: 587
    domain: smtp.gmail.com
    authentication: :login
    user_name: [username]@gmail.com
    password: [password]

However, you should add following line to enable TLS, which is required by Gmail service.

enable_starttls_auto: true

And finally, the configuration should look like this

production:
  delivery_method: :smtp
  smtp_settings:
    enable_starttls_auto: true
    address: smtp.gmail.com
    port: 587
    domain: smtp.gmail.com
    authentication: :login
    user_name: [username]@gmail.com
    password: [password]

development:
  delivery_method: :smtp
  smtp_settings:
    enable_starttls_auto: true
    address: smtp.gmail.com
    port: 587
    domain: smtp.gmail.com
    authentication: :login
    user_name: [username]@gmail.com
    password: [password]

UPDATED: changed nable_starttls_auto to enable_starttls_auto pointed out by stephane.