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