Monday, July 19, 2010

Authenticating MVC 2 JSON Services from Win Phone 7 with OAuth Lite


One of the challenges I've been facing with using an ASP.Net MVC 2 site to return JSON data to my Win Phone 7 app is authenticating my requests. I don't want other people to be able to sniff on the data between my app and the server and start making malicious requests.


I started looking into a custom AuthorizeAttribute after spending most of last week looking into OAuth authentication methods for the FatSecret.com API service wrappers. If you're not familiar with OAuth, take a minute to read up on it.


I decided that I wasn't going to use the full OAuth authentication strategy, specifically, I boiled it down to three parameters and an HMACSH1 Hashed Signature. Basically, my signature format is this {HTTPMethod}&{ServiceURL}&{LimitedParmString}. Where my LimitedParmString consists of a standard OAuth "Nonce", a Timestamp (seconds from Jan 1, 1970 UTC), and your consumer key. My client (a Win Phone 7 app in this case) includes this signature as a request header called "oauthlite" when they make their service requests to the MVC Website.


On the server side, my custom AuthorizeAttribute named OAuthLiteAuthenticate takes the HTTPContextBase and constructs a signature based on a request header called "oauthlite". The custom request header is just a url encoded parameter string with the 4 parameters; the "Nonce", Timestamp, Consumer Key and Signature Hash computed by the requestor.


Here is an example "oauthlite" header:



You can get the gist of the authentication process by taking a look at this in-memory implementation of an OAuthLiteAuthenticator:




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;

namespace OAuthLite.Server
{
/// <summary>
/// An in memory OAuthLite Authenticator example.
/// </summary>
public class OAuthLiteDictionaryAuthenticator : IOAuthLiteAuthenticator
{
// An "in-memory" key repository.
private Dictionary<string, string> _keyRepository = new Dictionary<string, string>()
{
// We only have one client, but you could add more.
{ "8b84444fbc09448da68ca14f000695cb", "83fbf4ea05df427bb3390d6d9a0fc626" }
};

private static string UrlFormat = "{0}://{1}";

#region IOAuthLiteAuthenticator Members

public bool Authenticate(HttpContextBase context)
{
if (context == null
|| context.Request == null)
return false;

var requestUrl = context.Request.Url;

var apiUrl = String.Format(UrlFormat, requestUrl.Scheme, requestUrl.Host);
var method = (HttpMethod)Enum.Parse(typeof(HttpMethod), context.Request.HttpMethod.ToUpper());

var header = context.Request.Headers["oauthlite"];

// We expect a parmstring including the signature.
if (String.IsNullOrEmpty(header)
|| !header.Contains("&"))
return false;

Dictionary<string, string> parms = new Dictionary<string, string>();
foreach (var parm in header.Split('&'))
{
string[] s = parm.Split('=');
if (s.Length < 2)
continue;

parms.Add(s[0], s[1]);
}

if (!parms.ContainsKey("signature") || !parms.ContainsKey("key"))
return false;

var signature = HttpUtility.UrlDecode(parms["signature"]);
parms.Remove("signature");

var key = parms["key"];

var secret = GetSecretByKey(key);

if ( string.IsNullOrEmpty(secret) )
return false;

return OAuthLiteHelper.ValidateSignature(signature, method, apiUrl, secret, parms);
}

private string GetSecretByKey(string key)
{
if (!_keyRepository.ContainsKey(key))
return null;

return _keyRepository[key];
}

#endregion
}
}



I've updated the Win Phone 7 JSON Services code example to use the new OAuthLiteAuthenticate attribute on an action called "Secrets" on the Product Controller. You can download the example below.




Download the code





Now Playing: Foals - Spanish Sahara


No comments:

Post a Comment