WSSE Authentication and Apache

13 December 2007   1 comment   Python

Powered by Fusion×

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: sha, binascii and 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 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 : semi-colon.

The solution was to not use base64.encodestring() and base64.decodestring() but to instead use base64.urlsafe_b64encode() and base64.urlsafe_b64decode(). Let me show you:

>>> import base64
>>> x = 'Peter'
>>> base64.encodestring(x)
>>> base64.urlsafe_b64encode(x)
>>> base64.decodestring(base64.urlsafe_b64encode(x))

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.


Joris Kluivers
You posted this a while back already, but just in case someone comes across this post.

I suggest using base64.standard_b64encode instead of the urlsafe one. I found that urlsafe_b64encode uses an _ instead of a / character in its character set.

Your email will never ever be published

Related posts

geopy distance calculation pitfall 10 December 2007
T-Mobile MMS collection 14 December 2007
Related by keywords:
Find song by lyrics 01 June 2004
Github Pull Request Triage tool 06 March 2014
Speed of DoneCal API (over 1,400 request/sec) and HTTPS (less than 100 request/sec) 27 December 2010
All your images are belong to data uris 06 January 2013
How I made my MongoDB based web app 10 times faster 21 October 2010
Why Django and Grok matters 02 February 2008
My first Twitter app - 22 September 2009
What I like and dislike about Grok 11 April 2008