WSSE Authentication and Apache
13 December 2007
I recently wrote a Grok application that implements a REST API for Atom Publishing so that I can connect a website I have via my new Nokia phone has LifeBlog which uses the Atom API to talk to the server.
Anyway, the authentication on Atom is WSSE (good introduction article) which basically works like this:
PasswordDigest = Base64 \ (SHA1 (Nonce + CreationTimestamp + Password))
This is one of the pieces in a request header called
Authorization which can look something like this:
Authorization: WSSE profile="UsernameToken" X-WSSE: UsernameToken Username="bob", PasswordDigest="quR/EWLAV4xLf9Zqyw4pDmfV9OY=", Nonce="d36e316282959a9ed4c89851497a717f", Created="2003-12-15T14:43:07Z"
What I did was I wrote a simple Python script to mimic what the Nokia does but from a script. The script creates a password digest using these python modules:
base64 and then fires off a POST request. Here's thing, if you generate this header with
base64.encodestring(ascii_string) you get something like this:
Notice the extra newline character at the end of the base64 encoded string. This is perfectly valid and is decoded easily with
base64.decodestring(base64_string) by the Grok app. Everything was working fine when I tried posting to
http://localhost:8080/++rest++atompub/snapatom and my application successfully authenticated the dummy user. I was happy.
Then I set this up properly on
atom.someotherdomain.com which was managed by Apache who internally rewrote the URL to a Grok on localhost:8080. The problem now was that the
Authentication header value was broken into two lines because of the newline character and then the whole request was rejected by Apache because some header values came without a
The solution was to not use
base64.decodestring() but to instead use
base64.urlsafe_b64decode(). Let me show you:
>>> import base64 >>> x = 'Peter' >>> base64.encodestring(x) 'UGV0ZXI=\n' >>> base64.urlsafe_b64encode(x) 'UGV0ZXI=' >>> base64.decodestring(base64.urlsafe_b64encode(x)) 'Peter'
If you're still reading, then hopefully you won't make the same mistake as I did and wasting time on trying to debug Apache. The lesson learned from this is to use the URL safe base64 header values and not the usual ones.