One of the nice things about Microsoft Windows Azure services is that they have a very well-defined and consistent REST API, meaning that they can be accessed from any language which can formulate an HTTP request; pretty much any language you can realistically expect to build an application in today. So as well as accessing the storage services from .NET/Silverlight CLR (or DLR) languages via the official SDK, you can access them from Rich Internet Applications written in HTML5 and Javascript, or from mobile phone services using Compact Framework, Java, or even Objective-C if you're doing penance for past-life atrocities against entire galaxies.
The only slight catch is that you have to authenticate the request, which involves some slightly complicated hashing of certain values with certain keys and which, if done in the wrong order, won't work. So I hope here to present a definitively working process for anybody else who is having bother and for me the next time I need to implement this in another language or framework.
Before signing, you need to make sure you've got the request headers right. You will need
There are two levels of signing: Shared Key, which involves the full set of headers and canonicalized headers and the resource being acted upon; and Shared Key Lite, which involves hashing a subset of headers and the resource being acted upon. We are going to use Shared Key Lite, because it is easier and because it works. Don't feel bad about not using the "real" Shared Key; the .NET Client Library for ADO.NET uses Shared Key Lite, so it must be OK.
The headers you need to include before signing are:
- content-length: either the length of the XML body of the request, or 0 if there is no body.
- x-ms-date: the current date and UTC time, formatted like this - "Thu, 11 Mar 2010 15:35:12 GMT". This time must be within the last 15 minutes when Azure processes the request.
If there is content in the body of the request then you need a content type header:
- content-type: application/atom+xml
If you are doing an Update against a Table entity (i.e. a PUT request) then you should also include:
This forces an unconditional update; if you wish for a conditional update, replace "*" with some criteria in the same format you would use for a query.
You are now ready to sign your request. You will need:
- The Shared Access Key from your Azure Storage project, which will probably be a base-64 encoded string;
- An implementation of the SHA256 algorithm.
The signing process involves constructing a Hash-based Message Authentication Code, or HMAC, by hashing together the Shared Access Key and a string made of bits of the request using the SHA256 algorithm. If you are using .NET, you can use System.Security.Cryptography.HMACSHA256 to do this quite easily. If you are using something else, it might have a standard library class to handle it. If not, and you need to roll your own, you can find pseudocode describing the HMAC algorithm here.
The string made of bits of the request is, more accurately:
- the date as it appears in the x-ms-date header
- a newline character (\n, not the CRLF combo)
- your account name
- the path (and any query parameters) of the REST resource URI
For example, for an insert:
Thu, 11 Mar 2010 15:35:12 GMT
myazureaccount/mytable
or for a query:
Thu, 11 Mar 2010 15:35:12 GMT
myazureaccount/mytable?$filter=(foo eq 'bar')
Calculate the HMAC for this string, convert to Base 64 encoding, and then add it as a header to your request in the form:
- Authorization: SharedKeyLite myazureaccount:q9324jr0+93qwfk+4ou93r8wsrf89owuj3f==
Your request is now signed and good to be accepted by the Windows Azure Table Storage service for the next 15 minutes.
The Blob and Queue services use similar authentication, but with more headers. I haven't yet implemented these services as direct REST calls yet, but when I do I'll post an update.
Part 2 of this series of posts will cover creating the body of requests for Insert and Update operation, and parsing the body of responses for all operations.