WSSE Authentication and Apache

13 December 2007   1 comment   Python

Mind That Age!

This blog post is 10 years old! Most likely, its content is outdated. Especially if it's technical.

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:

quR/EWLAV4xLf9Zqyw4pDmfV9OY=\n

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 : 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)
'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.

Comments

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.
Thank you for posting a comment

Your email will never ever be published


Related posts

Previous:
geopy distance calculation pitfall 10 December 2007
Next:
T-Mobile MMS collection 14 December 2007
Related by Keyword:
Ctags in Atom on OSX 26 February 2016
Best Atom packages of 2015 22 January 2016
Best non-cryptographic hashing function in Python (size and speed) 21 February 2015
Github Pull Request Triage tool 06 March 2014
All your images are belong to data uris 06 January 2013
Related by Text:
Connecting with psycopg2 without a username and password 24 February 2011
Headsupper.io 05 December 2015
Github Pull Request Triage tool 06 March 2014
Loadtesting this site and compare with static Apache 15 October 2003
My tricks for using AsyncHTTPClient in Tornado 13 October 2010