OAuth and the 4 hour work day

I must admit that I’m quite fond of the 4 hour work day. With that I don’t mean working excatly 4 hours per day, but the principle as explained by Scott Young. Come to think of it, the 4 hour part isn’t important at all, it’s the daily todo lists I like. I understand the desire to limit the actual time working if you hate what you do, but I am excited about my work and rather enjoy spending time on it.

On a given day, I start out making a list of the things I want to achieve on that day. If I get through my todo lists correctly every day in a week, I will successfully complete my (scrum) sprint. Of course, since I’m developing from scratch, estimation is much easier than it would be if I were surrounded by legacy systems. Interestingly, I normally overestimate and end up completing tasks much faster than expected. Maybe the standard software developer estimation factor (multiply the estimate by 3.14) is a result of reasonable estimates meeting legacy systems.

This was meant to be about OAuth and not estimation I suppose. The spec is a bit too much to go into here. OAuth is:

An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.

Letting OAuth speak for itself rather than trying to explain it with my own words felt good.

When needing to support OAuth authentication on our servers, I started out developing a consumer in Ruby as a Rack application. To test it, I used Agree2 since there is an excellent tutorial using Agree2 as an example service. Following the tutorial, I had a working consumer faster than estimated. The next step was to get my own OAuth Server running as a Rack application. Now this was a gauntlet run. First, I needed to get the communication sequence right. That wasn’t too hard, but I missed my estimates slightly. Next up was to start making things secure by verifying and signing messages. At this point things slowed down substantially. I had to read parts of the spec again and again while staring at my code. I eventually got my Rack based consumer to authorize with my Rack based server. All estimates were off, but at least it was working.

I know that our customers will use various systems to talk to our service. We expect to develop plugins for our service in their systems ourselves, and that means we should do the OAuth support as well. Our pilot customer has a PHP based system so the next step was to make the plugin for that system use OAuth. This was also the time I implemented verification of signed requests on the server side. I’ll cheat again with the description of the signature base string which is the basis for the signature:

The Signature Base String is a consistent reproducible concatenation of the request elements into a single string. The string is used as an input in hashing or signing algorithms. The HMAC-SHA1 signature method provides both a standard and an example of using the Signature Base String with a signing algorithm to generate signatures. All the request parameters MUST be encoded as described in Parameter Encoding (Parameter Encoding) prior to constructing the Signature Base String.

The OAuth spec is pretty specific on most things, but there are a few things that can cause problems when you start signing messages. Getting HTTP Get requests to work when signed was pretty straightforward. HTTP Post was worse. First of all, I am used to posting JSONs directly without thinking key, value pairs. This has interesting side-effects when the PHP library treats the JSON as a key and sorts it before the HTTP authentication parameters in the signature base string while the Ruby library sorts it after the HTTP authentication parameters. The PHP Consumer Tutorial I followed suggested you just convert your payload to a simple array. Surprisingly my JSON ended up not being included in the signature base string generated by the PHP library at all. The Ruby library however included it which is of course the right thing to do. The solution was to use an associative array with key ‘payload’. This was included in the signature base string by both the PHP and Ruby libraries. I had full functionality.

Next up is the handling of space in URLs. PHP is fond of encoding spaces as plus signs: “Alfa Romeo” -> “Alfa+Romeo” while Ruby tends to use the arguably more correct %20 encoding: “Alfa Romeo” -> “Alfa%20Romeo”. To my surprise, I never had any problems with this. I did have URL encoding issues, but they weren’t as simple as this.

After deploying my Rack applications to Passenger Phusion and Apache, the Ruby library started complaining about http://localhost/Some Name/something” not being a proper URI. URI(is not URI?) is what it said. Now it was easy to see that the space was the problem, but not how it became a problem. After scanning through the library, I found that it uses the parse method of the standard Ruby uri module to verify correctness of URLs. Furthermore I found that it uses env['PATH_INFO'] to generate the “/Some Name/something” part of this URL. I tried to use CGI.escape on this value, but that escaped a bit too much. The sad, but working solution was to substitute ‘ ‘ with ‘%20’ like this: request.path_info = env['PATH_INFO'].gsub(' ', '%20')

Now everything works perfectly with my PHP consumer. A few questions remain. The first and most important question is whether I trust these libraries after struggling like this. The easy answer is that I do. There are no security issues, just some pain and bloodshed needed to get them to work. The next question is what happens when we need to support consumers in ColdFusion Markup Language, ASP and other web scripting languages. I don’t know the answer to that. I guess the experience working with PHP will be helpful, but I also expect other pitfalls to show up. Time will tell.

Now what has this OAuth stuff got to do with the estimation and 4 hour work day principle I started with? Actually a lot. While OAuth isn’t exactly a legacy system, the added complexity was comparable. Getting the handshaking to work properly was straightforward and implementation was similar to what I expected and this is the part I actually estimated. When I got to the cross language part and request signing, I encountered a string of unexpected hurdles much like you would see developing in a legacy system. If I were to follow the 4 hour work day principle mindlessly, I would have had to do a couple of all-nighters in a row. I do believe my estimation was off by a factor of around 3.14 on average.

Advertisements

5 thoughts on “OAuth and the 4 hour work day

  1. By the way what wa your total estiamte to build a fully functional 3 legged OAuth Authentication with User Authorization?

  2. Hello – just curious to understand, how long did it take you to build a 3 legged OAuth Auth framework in terms of time estimates as we are aswell in a scrum development methodology

  3. I originally estimated three days to get the OAuth up and running, but had it up in less than a day. It was about two weeks later before the full request signing between PHP and Ruby was working. Since getting this right is important, I would set aside a week to ensure it’s well tested and robust.

  4. Thanks for quick turnaround. Also wanted to ensure, it had
    1) user’s authorization via Login page.
    2) did you store all the request/access tokens in db
    3)Did it include a website for users to revoke access to apps when needed?

  5. The OAuth system included a login page implemented in haml and based on the haml template for the rest of the site. I stored all persistent data including request, access tokens and remote service credentials in CouchDB.

    I did not add the user page to revoke access at the same time, but the basic support for that was included. Adding it meant another haml view and some basic sinatra post handling. This addition was probably a couple of days work.

    Sticky sessions in the load balancer will avoid problems related to request tokens not being synchronized between database replicas in time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s