I was excited to learn recently that the Nokia N73 can speak AtomPub, and that a friend of mine owns one. I thought I'd try to make it talk to the new AtomPub implementation in WordPress, but reading through the N73 documentation I found that it only supports WSSE authentication, and WordPress only speaks HTTP Basic Authentication. I'd never heard of WSSE, but Mark Pilgrim has a good write up on XML.com, and the Ape has the ability to speak WSSE, so I thought I'd implement it in WordPress. Bear in mind that I'm not writing this from a security point of view, I'm just looking at authentication as a necessary evil to get cool AtomPub things working. And there's a spoiler: it can't be done :)

A WSSE client will send an Authorization header which, as we know, will get dropped if Apache is passing the request off to a CGI, and a X-WSSE header that looks like this:X-WSSE: UsernameToken Username="USERNAME", PasswordDigest="PASSWORDDIGEST", Nonce="NONCE", Created="2007-09-08T05:52:36Z"

PasswordDigest is a base64 encoded SHA1 digest of the concatenation of the nonce, the timestamp and the password. The nonce is of course some random string.

So, to add WSSE into WordPress AtomPub, we can add some code to the authentication function in wp-app.php.

First, we check if the client is trying to authenticate using WSSE by looking for a X-WSSE header.if(isset($username_token = $_SERVER['HTTP_X_WSSE'])) {

We then take the Username Token contained therein and split out the user, digest, nonce, created information sent by the client. There are probably nicer ways to do this. $wsse = array( 'user' => "", 'digest' => "", 'nonce' => "",
'created' => "", 'password' => "");
$tokens = explode(", ", trim(strstr(stripslashes($username_token), " ")));
foreach ($tokens as $token) {
$pivot = strpos($token, '=');
$key = substr($token, 0, $pivot);
$value = trim(substr($token, $pivot + 1), '"');
switch ($key) {
case "Username":
$wsse['user'] = $value;
break;
case "PasswordDigest":
$wsse['digest'] = $value;
break;
case "Nonce":
$wsse['nonce'] = $value;
break;
case "Created":
$wsse['created'] = $value;
break;
}
}

Finally, we recreate the digest on the server, and compare it to what was sent, and close the if. $wsse['password'] = get_password_by_login($wsse['user']);
$server_digest = base64['encode(pack("H*", sha1($wsse['nonce'] . $wsse['created'] . $wsse['password'])));
if ($server_digest == $wsse['digest']) {
$login_data = array('login' => $wsse['user'], 'password' => $wsse['password']);
}
}

If you have familiarity with WordPress's code, you might be saying something like, "WTF is this get_password_by_login() function call? I've never seen such a thing!" Good question. And the dirty little secret is that no such function exists. A weakness of the WSSE authentication scheme appears to be that to recalculate the digest the password needs to be stored in plain text on the server. This is probably at least as bad as sending the password in plain text over the wire, the thing that WSSE is trying to avoid. WordPress, sensibly, does not store passwords in plain text, but computes an md5 hash of them and stores that.

So, as far as I can tell, there is no way to implement WSSE in WordPress in any sensible way.

One little word on security. If we could implement WSSE, the code should keep track of nonces and make sure they aren't repeated, and should reject UsernameTokens created more than a couple of minutes ago (leaving aside any discussion of synchronisation of your client's clock with my server).

P.S. I hadn't read Joe Cheng's comment or Joseph Scott's reply in the comments of the post I linked to above before I started off on this wild goose chase.