[go: up one dir, main page]
More Web Proxy on the site http://driver.im/

OAuth, here she comesOAuth, here she comes

The best thing about globalization and cheap computing is we no longer have to resort to cinematic caricatures to explain computer security to mainstream society. Everyone on the internet has, in some way, been touched by the clammy hand of a script kiddie: Your mom’s e-mail is flooded by product offers for insecure men, sent from some busted home PC. Celebrity accounts of all kinds are routinely broken into, exposing dull private lives and elementary writing abilities. And Vista—it needs your permission to execute that instruction.

If that’s not enough, Twitter has sailed in trailing fresh meat for web sharks: accounts of significant value operated by computing amateurs through a variety of devices and applications, users who blithely grant publishing abilities to autonomous web-bots. What could possibly go wrong here?

Alice doesn’t live here anymore, and neither does Bob

Web APIs created a need for a new authorization protocol, so that users can grant access to third parties without sharing their primary credentials: OAuth fills this need. It does so in a pretty simple way, but as a new technology it takes most of us a little time to wrap our heads around exactly how it works. So in 2007 a beginner’s guide was published including a walk-through starring Jane, a jellybean-person whose enthusiasm for Scotch is subtly indicated by a comped-in photo of a liquor bottle—much like Barbara Walters’s Grand Marnier in Auto-tune the News #3. Jane really wants to draw arrows from one isometric projection of a 1990s PC ‘tower’ to another, and use Windows 3.1 Media Player.

But these days we have dozens of OAuth web services IRL—you are the jellybean. You can turn your Twitter icon green to support Iranian democracy, and you can do it without giving away your password! For us programmers, there a dozen OAuth libraries in different languages, and a half-dozen in Java alone for various underlying HTTP libraries. Whoopee!

On the other hand, if you don’t want to use any of these OAuth cake mixes because you are are a wretched programming eccentric, it’s wee bit cold out. The Scotch-sipping guide doesn’t go into enough detail for you to implement the protocol. The main Java implementation is something of a nesting doll, hard to follow through the flow through the layers of transport abstraction. This single-file Python example is the most readable one out there, and it’s live.

But surprisingly to this writer, who has never really tried to read a protocol specification, the easiest way to implement OAuth was to do just that. In these exciting times of session fixation, the correct specification is OAuth Core 1.0 Rev A Draft 3. (Read it and weep, session perverts.) The text is somewhere between Ulysses and Twilight in difficulty—and far more practical than either. If you’re confused about any part of the OAuth process, save yourself some time and go to the source.

Your signature, please

Like most respectable protocols, OAuth is a stout little tower of layered abstraction. As a whole it’s a little intimidating, but on the HTTP ground floor OAuth is just a standard for signing requests. And since web APIs are fully driven by HTTP requests, it is awfully handy to be reasonably certain that an instruction was signed off by a particular entity.

The HMAC-SHA1 signing method is the one to learn. Clients use a one-way hash with one or two secret keys to sign a message that fully describes the request (method, URL, and parameters). When a service receives the request, it generates an identical message from the component parts. As the service has no direct access to the message, there must be no ambiguity in the process to derive it from the request. The service must also be able to produce whatever secret keys were used to hash the message. As it was the service that created them in the first place, that’s generally a matter of looking them up by the non-secret keys included in the request.

The only tricky part of this process, assuming you have an SHA1 implementation at hand, is correctly assembling the message. The parameters it signs can include query-string and POST parameters. Instead of trying to keep these separate and in their original order, the spec calls for them to be combined and alphabetized by key. While this reordering seems fussy in the simplest cases, it avoids a need for special handling of the complicated ones.

Parameters going into the signed message are encoded in the regular way for query strings and posted forms, as percent-encoded name-value pairs. The three parts of the request to be signed are then percent-encoded (for parameters, it’s their second time) and joined by ampersands. By following this procedure the client and service are able to distill the same sequence of bytes from the request and, using the secret keys known to both of them, the same signature of it.

As mentioned above, the server needs some OAuth-specific information to verify the signature, the keys to look up the secret keys, so a set of OAuth parameters is added into the request before signing it. In the end, a singed request looks like the original request with non-secret OAuth parameters attached as well as a signature—everything but the signature parameter itself is represented in the signature.

Here is a request signing function in Scala:

It returns returns only the OAuth parameters, which you could add to other request parameters or put in an Authorization header as recommended by the spec.

Courtship rituals

Signing requests is great, but if that were all there were to OAuth it would be a Vegas wedding chapel of web-service security. For the signatures to have any meaning, the service and the consumer (that Twitter client you’re going to write some day) have to go through a routine. It is modeled on the venerable romantic comedy genre of film.

First, the service issues you the programmer a consumer key and secret; this is your license to love. Then, you’re approached by an attractive user. You want to have a relationship with this user, one that is recognized by the service, and the user feels the same! That’s sweet, but hold your horses.

You must submit your request to the service, signed as a consumer. If you’re also a web service, you include a user-specific callback URL here so you know which user this was after you’re married. (Yes: this OAuth analogy implies polygamy.) The service then issues a request token.

So now you think you are in the clear to get busy with this user now, right? Ha ha, dream on. It turns out the user’s cat hates you, and there is another programmer, and some unlikely thing happens that causes you and the user to doubt each other’s affections—letters are lost and trains are missed. Basically, it is uncertain times for you two!

This dramatic tension can only be resolved with an authorization request. You have to send the user to the service holding the request token—you can’t do this yourself! No, the user has to walk right up to that service, log in or whatever, and ‘consent’ to a read and possibly write interaction with you. The user will hem and haw, then decide that true love is more important than the cat or the other programmer’s fancy ways, and agree to the relationship.

The user calls you back at the address you gave, plus the request token and a verifier. You’re together, but the hijinks are not over yet. (Oh, Hollywood.) You have to go back to the service with an access request signed with your consumer and request tokens and including the verifier—ugh. But a happy ending is a foregone conclusion at this point; we are just teasing the audience and they know it. The service responds with the long-sought access token. Finally, your app has access to the user’s details and you all live happily every after.

Just keep in mind that divorce is only a mouse click away.

Carte bl@nche

You know how the implicit keyword makes everyone crazy? Like most features Scala supports that Java does not, it is met with suspicion and even hostility by enterprise tourists. Isn’t it so confusing? Isn’t it some kind of hack? Isn’t it … like C++? (Now that is just wrong.)

Even Scala adepts can be coy about implicit. Don’t write your conversions too broadly and import them all over the place, kids, or you will regret it! (Who has done this?) But Haskell fugies and other typists have a very different attitude: implicit conversions are fundamental. They aren’t a workaround for type corners or a way to fake open classes; they are an everyday tool in an adequate type system: use them with care like any other feature.

What are these functionistas smoking? Immutable objects, as usual. When you try to make a class internally immutable, like Databinder Dispatch’s Request class, you end up writing a lot of methods that return new instances of that same class. (The serious lambda kool-aid club thinks in ‘modules’, but we are only three drinks in.)

This presents an interesting problem for extension by subclass. Actually, not interesting—more like sucky. Maybe you can fix it with existential types, self types, or Ionesco-typing where everything is a rhinoceros so the return values don’t matter and the point is just to LIVE… but implicit gives us a way to steer clear of the whole mess. In the same way implicit conversions can extend libraries you couldn’t otherwise extend, they’re an excellent first-resort to the the problem of planned extension here described.

Consider this desired expression of a Dispatch request:

val svc = Twitter.host / "oauth"

def request_token(consumer: Consumer) =
  svc.secure.POST / "request_token" <@ consumer as_token

The secure transport and parameterless post methods are new, but they are generally applicable and so have been added to Request. The signing method <@ is not general, nor is as_token which returns a Handler that eventually returns a Token object. How can these operators be added to Request without it having to inappropriately import OAuth?

You probably guessed it: implicit conversions! A class that wants to use such operations can bring them into its own scope, so that the core functionality remains unfettered (and could be distributed as its own core module, for example). If you could do this through inheritance that would be fine, but it doesn’t work and implicit does so that’s the deal. Regard:

When the implicit conversion is in scope, a <@ operation on Request is transformed into new RequestSigner(request) <@ and after that things are the same as if they’d been defined on Request itself. Everything is statically compiled and checked; at runtime it’s like we wrote out the longer form. Which is to say, if you think this is a vicious hack you must be pretty bored.

By the way, check out the split_decode method it is some functional good times. It transforms name-value parameters into an immutable map. Passing an unapplied method like Http.-%, which does a percent decode, directly to map is just rad. And that’s immediately followed by sequence matching! It’s almost too awesome as it is, but, if anyone knows a slimmer way than immutable.Map.empty ++ (...) to make that sequence into a Map, please post it to the comments.

This same technique has also been applied to the JSON ># operator, freeing dispatch.Http of its only other Dispatch import. Modularization, here we come, in a few weeks or whenever.

This one goes out…

Needless to say, Dispatch’s 0.4’s Twitter interface supports authentication. There are also some specs against a test server using the OAuth signing ops directly which you could do with any service, for fun and profit.

Ummmmm special thanks to simple-build-tool. Without its steadfast support through all those recompiles, Dispatch’s OAuth support would not be where it is today. And thanks to Scala X-Ray for dressing up the source files. And also Jane, for being a boozy jellybean, and auto-tuning, and…

Please make a webapp that layers Grand Marnier bottles on Twitter icons, to support Barbara Walters. Thank you.

Codercomments

Nice post. Is the title of your post a reference to Tim and Eric, by chance?

http://snackfeed.com/videos/detail/33393f7e-d881-102b-a525-00304897c9c6/Here-She-Comes-2s=s

Thanks!

No, I haven’t seen that video before. it is quite an assault on the senses.

Dude, that was a fun read. I love your humor. I never thought of security in ‘romantic’ terms - comedy yes, but most often as a porn-orgy I’d rather never want to see or participate in. Great blog post.

…the orgy-part as in “the state of in-security on the web and ignorance of common users today”.

Let’s not bring CouchDB into this. ;)

Hey! What a great blog, blog-post and code! I am so glad to know there’s people out there doing this kind of experiments with scala and http/dispatch/request/oauth/twitter!!!

I would love to be in contact and read more about the development of the whole dispatch library! If you would accept code on Twitter.scala i would love to wrap all the api around!!!

Also; any idea why the dispatch library wont work in the google app engine(for example http://twitknow.appspot.com/OAuth/login works in my server and localhost but refuses to work on the GAE)

Cheers!

I would LOVE some code to fill out the Twitter interface in Dispatch. Please fork off git://technically.us/git/dispatch and I’ll pull your changes into the next release!

As for GAE, I haven’t tried but it is probably the threading limitations? I would try using the Http singleton as well as single-threaded instances. If neither works, the problem & solution is probably somewhere in HttpClient 3 (beta). If you can figure out how to get that working on its own I can fix it in Dispatch.

Well, i found a hosting where it works(stax) and its in beta(free beta). So I’ll make a twitter game this weekend and test this puppy under pressure.

Also I’ll be glad to fill in some code in the git repo!

Cheers and you sure have a permanent reader of anything you write in the future =)

Allright, im having trouble adding post variables to a request, what would be the correct way to add a update status to the status class in the twitter.scala file?

def update(consumer: Consumer, token: Token, message: String) = this / “update.json” « Map((“status”,message)) <@ (consumer, token

Doesnt seem the work, any ideas?

(If i get that working i’ll be able to wrap all the api around twitter.scala =)

That looks right, and it works for me. Could you send me an e-mail about this, address at the bottom of the left column?

Thanks n8!

I have used this successfully in my app 1 and it was pleasure to work with.

The only thing I had to modify was removing the oauth_verifier while fetching the auth token. I guess the verifier is required for desktop-apps but not for web-based apps.

Very cool, I like the app!

It’s been a while since I walked through the webapp flow but I think the verifier is passed back after the authorization step? It’s not required by twitter currently for webapps but it is required by the changes in the 1.0a spec, as I read them, so they could make it required at any time.

If you want to chat about this further, perhaps the forum would be suitable?

Add a comment