středa 17. srpna 2011

DotNetOpenAuth and Url rewriting (in Azure)

I have created a simple OAuth provider for my web application using DotNetOpenAuth just the way that I described in this last post. On local everything worked just fine. However when I published the solution to Azure then I obtained errors while processing authorized request.

Well the error happend because I used the idea of specifing exact scope within each token, which says what URL the consumer application has right to access. So to each Access Token a String value representing the scope is added representing the URL which the application has right to access. When the consumer application demands data from certain web service, than the Authorization Manager checks the scope of the access token which was added to the request.
The problem comes when the server which is hosting the OAuth data provider performs some URL rewriting. In that case the URL which is being accessed had changed in the HTTP pipeline and the provider has to take care of that. The URL of each request comming to Azure changes inside.

If you take a look at the Authorization Manager code from the DotNetOpenAuth you will see that it checks the scope of the incoming message.
public class OAuthAuthorizationManager : ServiceAuthorizationManager
{
  protected override bool CheckAccessCore(OperationContext operationContext)
  {
    //check the access token etc...
    //scopes containes the scopes added to the access token
    if (scopes.Contains(operationContext.IncomingMessageHeaders.Action)) {
      return true;
    }
  }
}

And that is actually the problem, while operationContext.IncomingMessageHeaders.Action contains the URL after rewrite and the consumer application usually specifies the URL which it wants to access in the form before the rewrite.

What I found as a solution to this issue was to use instead this piece of code
Uri requestUri = operationContext.RequestContext.RequestMessage.Properties.Via;
...
...
var action = requestUri.AbsoluteUri.Substring(0, requestUri.AbsoluteUri.IndexOf("?"));
if (scopes.Contains(action))
{
    return true;
}

Using DotNetOpenAuth to create OAuth Provider

Download the source code from GitHub.
DotNetOpenAuth is an open source library created and managed by Andrew Arnott which gives you the
possibility to use OAuth protocol, OpenID and ICard. It si powerful - and comes with a nice Samples package. Recently I needed to implement OAuth provider, in other words I wanted to allow third party application to obtain data from my application after the user authorizes them to do so.

Before I have implemented that for my application, I have created a simple Proof of Concept (POC), which I will share with you. Basically it is just a simplified version of the OAuthProvider project in the Samples package. That is a greate example, however one fact, that might be little confusing is that it uses Linq to SQL to store the authentication Tokens and if you do not want to enter into that you might get lost. My targeted application uses NHibernate for ORM, but I decided to make the POC only store data in the memmory to keep it as simple as I could.

At the end I will just lay out how I incorporated DotNetOpenAuth to my application, where I already had Data Access layer established using NHibernate.

To understand the rest of this post, you need to understand the basics of OAuth protocol.

Here is the standard way of communication between Consumer and Provider using OAuth protocol.



DotNetOpenAuth provides classes and structures which enable you to easily create OAuth Consumer or Provider and manipulate Tokens. However each both Consumer and Provider have to decide on how to handle and store the Tokens.

The basic scenario is this:
Provider exposes WCF service which is secured using OAuth protocol. Consumer can access this services only when he obtains authorization of the actual user and owner of the resources.
Here is a digram which shows the structure of OAuth Provider when implemented using DotNetOpenAuth.


There are two entities which perform the communication. First it is simple Http Handler which takes care of the OAuth "handshake". The second is the actual WCF service which uses custom Authorization Manager to perform the authentication. Both of these make use of the Service Provider (comming from DotNetOpenAuth). Service Provider than uses implementations of IServiceProviderTokenManager and INonceStore also defined in DotNetOpenAuth, which take care of the persistance of Nonces and Tokens. It is up to the programmer to decide how to implement these interfaces.

OAuth provider needs to store three types of objects: Consumers, Tokens and Nonces. To keep it simple, I decided to store all of them in memory in lists inside applications Global file.

public class Global : System.Web.HttpApplication
{
  public static List<OAuthConsumer> Consumers { get; set; }
  public static List<OAuthToken> AuthTokens { get; set; }
  public static List<Nonce> Nonces { get; set; }  
}

Now these list are then used by ServiceProvider, actually by IServiceProviderTokenManager and INonceStore, which later in turn are used by ServiceProvider. Lets first take a look at the IServiceProviderTokenManager interface (definition is here). For example the GetRequestToken method would be implemented like this:
public IServiceProviderRequestToken GetRequestToken(string token)
{

    var foundToken = Global.AuthTokens.FirstOrDefault(t => t.Token == token && t.State != TokenAuthorizationState.AccessToken);
    
    if(foundToken==null)
    {
        throw new KeyNotFoundException("Unrecognized token");
    }
    return foundToken;
}

So it is quite easy. The method actually returns IServiceProviderRequestToken, methods which work with Nonces or Consumer also return interfaces defined by DotNetOpenAuth, so in other words all of your business entities which encapsulate Consumer, Tokens or Nonces have to implement these interfaces defined by DotNetOpenAuth.

There are two types of tokens: Request Token (IServiceProviderRequestToken) and Access Token (IServiceProviderAccessToken). During the OAuth handshake, the request token is interchanged for the access token. So you can actually create one class which implements both of these interfaces. In that case implement these interfaces explicitely because there are Properties which have to be implemented with same name. There are two properties which are returning String called Token (one comming from Access Token and other from Request Token interface), here is the way in which they are implemented:
private String _token;
String IServiceProviderRequestToken.Token
{
    get { return _token; }
}

String IServiceProviderAccessToken.Token 
{
    get { return _token; }
}

public String Token { 
    set { 
        _token = value;  
    }
}

When the Token changes from Request to Access token, the actual String value stays the same. So I have backed up both of these properties by the same private field and added a property which will allows me to set this field.

Basically thats it. There is much more code around but actually I just took most of the code comming from the official set of examples.

Using NHibernate to persists Tokens, Consumer and Nonces

In the project where I needed to implement OAuth provider, I was using NHibernate as my ORM with NFluent(nice framework which allows to write configuration of NHibernate in C#). What I like about this combination is the fact, that there is no XML file and generated properties (such as with Linq2SQL).
I always try to keep my database entities as clear as possible, that is why I did not want my entities to implement the interfaces forced by DotNetOpenAuth. Instead of that I wrapped my entities by classes which are using these interfaces and use the database persisted entities as backup. So just to explain what I mean, here is the persistant class:
public class AuthToken
{
    public virtual int Id { get; set; }
    public virtual AuthConsumer Consumer { get; set; }
    public virtual AuthTokenState State { get; set; }
    public virtual DateTime IssueDate { get; set; }
    public virtual UserIdentity User { get; set; }
    public virtual String TokenSecret { get; set; }
    public virtual String Scope { get; set; }
    public virtual String Token { get; set; }
    public virtual String Version { get; set; }
    public virtual String VerificationCode { get; set; }
    public virtual DateTime? ExpirationDate { get; set; }
    public virtual String[] Roles { get; set; }
    public virtual String Callback { get; set; }
}
And here the DotNetOpenAuth compatible wrapper:
public class OAuthToken : IServiceProviderRequestToken, IServiceProviderAccessToken
{
    public OAuthToken(AuthToken token)
    {
        if (token == null)
        {
            throw new ArgumentNullException("Token passed to constructor of OAuthToken cannot be null");
        }
        Token = token;
    }

    public OAuthToken()
    {
        Token = new AuthToken();
    }

    public AuthToken Token {get;set;}

    #region IServiceProviderRequestToken

    Uri IServiceProviderRequestToken.Callback
    {
        get
        {
            return new Uri(Token.Callback);
        }
        set
        {
            if (value != null)
            {
                Token.Callback = value.AbsoluteUri;
            }
        }
    }

    string IServiceProviderRequestToken.ConsumerKey
    {
        get { return Token.Consumer.ConsumerKey; }
    }

    Version IServiceProviderRequestToken.ConsumerVersion
    {
        get
        {
            if (Token == null || Token.Version == null)
            {
                throw new ArgumentNullException("The Token or the Version are null");
            }
            return new Version(Token.Version);
        }
        set
        {
            Token.Version = value.ToString();
        }
    }

    DateTime IServiceProviderRequestToken.CreatedOn
    {
        
        get {
            return Token.IssueDate.ToLocalTime(); }
    }

    string IServiceProviderRequestToken.Token
    {
        get { return Token.Token; }
    }

    string IServiceProviderRequestToken.VerificationCode
    {
        get
        {
            return Token.VerificationCode;
        }
        set
        {
            Token.VerificationCode = value;
        }
    }

    #endregion

    #region IServiceProviderAccessToken

    DateTime? IServiceProviderAccessToken.ExpirationDate
    {
        get { return Token.ExpirationDate; }
    }

    string[] IServiceProviderAccessToken.Roles
    {
        get { return Token.Roles; }
    }

    string IServiceProviderAccessToken.Token
    {
        get { return Token.Token; }
    }

    string IServiceProviderAccessToken.Username
    {
        get {
            if (Token.User == null)
            {
                throw new ArgumentNullException("Token does not have assigned user");
            }
            return Token.User.Identification; 
        }
    }
    #endregion
}
In that case the Token Manager has to take care of the conversation with database as well as with wrapping the recieved entities.
public class DatabaseTokenManager : IServiceProviderTokenManager
{
  private IOAuthServices _oAuthServices;
  
  public IOAuthServices OAuthServices
  {
      get {
          if (_oAuthServices == null)
          {
              _oAuthServices = get your service class which talks to the database....
          }
          return _oAuthServices;
      }
  }
  
  public IServiceProviderRequestToken GetRequestToken(string token)
  {
      var authToken = OAuthServices.GetRequestToken(token);
      if (authToken == null)
      {
          throw new SecurityException("No token found: " + token);
      }
      return new OAuthToken(authToken);
  }
}
The rest stays the same and it works fine.
It took me some time to understand how DotNetOpenAuth on the provider site works. I hope this post can help someone to jump in fast.

Get the code from GitHub