Monday, August 24, 2009

Restful AtomPub Services with HTTP Basic Authentication in Azure

Implementing a service with an AtomPub interface on Azure is quite easy. As a starting point I used the PictureRestService example from:

http://code.msdn.microsoft.com/wcfazure/Wiki/View.aspx?title=PictureRestService

Next step is to restrict the access to the interface methods to a set of authorized users.

As a starting point for this I used:

http://msdn.microsoft.com/en-us/library/dd203052.aspx

As mentioned in this guide the first thing to do is to check if the request contains an user authentication. For this the HTTP request has to contain an "Authorization" header. For a basic user name password authentication the value of this header has to be the string "basic" followed by the user name a ":" and the password. User name, ":" and password are stored in a Base64 encoded string.

Here is an example which checks if the user is "eggeral" or "sven":

private bool AuthenticateUser(out string userName)
{
userName = null;
WebOperationContext ctx = WebOperationContext.Current;
string authHeader = ctx.IncomingRequest.
Headers[HttpRequestHeader.Authorization];
if (authHeader == null)
{
return false;
}
if (!string.IsNullOrEmpty(authHeader))
{
if (authHeader.StartsWith("basic ",
StringComparison.InvariantCultureIgnoreCase))
{

string userNameAndPassword = Encoding.Default.GetString(
Convert.FromBase64String(authHeader.Substring(6)));
string[] parts = userNameAndPassword.Split(':');
userName = parts[0];
string password = parts[1];

if (userName == "eggeral" && password == "secret")
{
return true;
}
if (userName == "sven" && password == "sven")
{
return true;
}

}

}
return false;
}


If the request does not contain an "Authorization" header we have to request one from the client (for example Firefox or Internet Explorer). This is done be answering the request with the status 401 Unauthorized and a "WwwAuthenticate" header which specifies the authentication mechanism. The client will then prompt the user for user name and password and resend the request to the service.

Here is the code which handles this for the "PutEntry" method:

protected override SyndicationItem PutEntry(string collection,
string id,
SyndicationItem entry)
{
string userName;
if (!AuthenticateUser(out userName))
{
WebOperationContext.Current.OutgoingResponse.StatusCode =
HttpStatusCode.Unauthorized;
WebOperationContext.Current.OutgoingResponse.
Headers.Add(
HttpResponseHeader.WwwAuthenticate,
"Basic realm=\"Task Management\"");
return null;
}
// Do some stuff and return an entry.

}


Of course basic authentication is not secure, but its an easy way to get started. For production systems implement a more secure method as described in Microsofts guide for Restful web services (link above).
Post a Comment