domenica 21 ottobre 2007

RESTful Web Services Example 3.16 - Signing the request

After little less than a month, let’s resume with the Squeak Smalltalk versions of the examples of the RESTful Web Services. This latest installment is so late due to a bug that I introduced in the CurlPlugin code when adding a new primitive, and it took me a long while to debug it. The new primitive is needed for the next example in this series.

We already know how to build a canonical string, and how to actually sign it. In today’s example, we’ll see how the request signature is created from the URI, the HTTP method, and the headers.
This is the task of the #signatureFor:method:headers:expires: method and its ilk.

The source for S3Object>>signatureFor:method:headers:expires: is the following:
S3Object>>#signatureFor: aStringOrUri method: method headers: headers expires: expires
| uri path |
"Builds the cryptographic signature for an HTTP request. This is
the signature (signed with your private key) of a 'canonical
string' containing all interesting information about the request.

Code taken from RESTful Web Services. Copyright © 2007 O'Reilly Media, Inc.
All rights reserved. Used with permission."

"Accept the URI either as a Squeak URI object, or as a string"
uri := aStringOrUri asURI.
path := uri query ifNil: [uri path] ifNotNil: [uri path, uri query].

"Build the canonical string, then sign it"
^ self signString: (self canonicalStringFor: method path: path headers: headers expires: expires)

The method is very simple, but there are a couple of observations that may be done.

The first observation is about the uri temporary variable: since the aStringOrUri parameter, as the name says, may be either a string or an URI, we send the #asURI message in order to be sure that uri holds an URI object (this way of ensuring that an object is of the appropriate class is a common pattern in Smalltalk).
Once we are sure we have an URI object, we extract the path from the URI, plus the optional query string (the part of the URI after the ? character).

Finally, we build the canonical string, sign it and return the signature.

The source code for this method is included in the RWS-gc.14 package in the RWS repository. In the same package you will find other variations of the same method:

`S3Object>>#signatureFor:method:headers:`
`S3Object>>#signatureFor:method:`
`S3Object>>#signatureFor:headers:`
`S3Object>>#signatureFor:`


If you browse the source code for these methods, you’ll observe that all these methods send the #signatureFor:method:headers:expires: message with the appropriate default parameters. This is a very common pattern in Smalltalk, but it has one serious flaw, as the sheer number of possible combinations makes this solution unpractical on a large scale. For example, a message with four parameters may have other 14 possible variants, while one with five parameters has 30 possible variants.

This combinatorial explosion is somewhat mitigated by the fact that usually there’s only a restricted subset of sensible and useful variants of a message, but in many cases this is not enough. This is one of the reason why Seaside moved from a builder system to a canvas one for (X)HTML generation.

In the next post in this series, we’ll see how to send a signed request to the Amazon S3 service.

Nessun commento: