echo "hey, it works" > /dev/null

just enough to be dangerous

Implementing WSSE authentication in WordPress


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.

Image search


[Update: A friend from Microsoft says, "The UI switches to a more basic scheme if you're using a browser that's not recognised, for example the Firefox 3 and IE8 betas. What are you using - can this be the explanation?" Ah, indeed it is, no need to panic.]

[Update: Live seemed to have turned off all the cool features and are back to boring image search. What happened?]

Of the three main search engines (Google, Yahoo! and Live) Live search is streets ahead when it comes to image search. They also appear to be the only ones who are doing much innovation in this space.

So, why do I say such a thing? I'm not really talking about the quality of their results, because they're all about on a par. Live has a much better user experience. The first thing you notice is that they have done away with the concept of paged results. No more clicking 'Next', you just keep on scrolling down and more images appear. This makes a lot of sense for images for three reasons. First, image search isn't great, so users are much more likely to want to see a lot more results than a normal search for a web page. Lots of clicky clicky next just gets tedious.

Second, a thumbnail is a much better summary of the actual resource than the summaries currently generated by search engines. This means that users are effectively looking at the answer as they scroll through the results. They don't have to click on the result link and go off to evaluate a document and then come back, they can evaluate the image in situ, and therefore evaluate a much larger number of resources.

Third, it's more likely that users are not looking for an individual image, but for different images of the same thing. When they find an image they like, it's quite possible that isn't the end of their search. This brings me to another plus of Live; the scratchpad. When you find an image you like, Live allows you to put that image in a scratchpad by clicking on an image and selecting the appropriate link. Once the scratchpad is open, you can drag and drop to it as well. You can then save the images as collections.

Other interesting things to note include the resizable thumbnail slider and the image size filter (including wallpaper-sized images). Last, try filter:face and filter:portrait.

PUT and DELETE dropped on the floor


I mentioned previously that the AtomPub server in my WordPress installation wasn't successfully deleting entries. More specifically, I get a 403 Forbidden when trying to PUT or DELETE posts or media files. I posted to the wp-testers mailing list and Joseph Scott passed the question along to Sam Ruby, Tim Bray, Elias Torres, and Pete Lacey, and I basically eavesdropped on their conversation.

Turns out that the problem is likely to be a firewall rejecting PUTs and DELETEs. This started a discussion of how WordPress should workaround the problem. Some options are URL munging, custom headers, or message in a message. All horrible for various and obvious reasons, and none going to make it into 2.3. Sam cautioned, and suggested revisiting PacePutDelete, a method proposed by Joe Gregorio on the Atom lists to overcome a lack of PUT and DELETE support on clients, which led me off on a fascinating journey through the Atom mailing list archives.

I'm not sure how big the problem really is now. It may take more time and effort to come up with a "fix" than it would to lobby purveyors of broken internet devices to really fix them. The biggest concern with a workaround, however, is that it may slow said fix. Why should we fix our firewall when your client can just use X-Method-That-Really-Is: delete? If such a workaround is implemented it should be a fallback in case a correct request fails.

It sure is frustrating that the solution is baked right in to HTTP.

Serving static files with Camping


Camping interprets every request to the server using the paths in the controllers, so if you want to serve static files, like external stylesheets or images, you need to provide a controller for them. Take this bit of Markaby:
img :src => 'images/logo.png'
This will get interpreted by Camping and end up with this HTML:
<img src='images/logo.png' />
When the browser reads that, it will send a GET request to the Camping server looking for logo.png, that Camping will try to match against the controller paths. If you haven't set one up, you'll get an error.

So, in your Controllers module:
class StaticImage < R '/images/(.*)' def get(static_name) current_dir = File.expand_path(File.dirname(__FILE__)) @headers['Content-Type'] = "image/png" @headers['X-Sendfile'] = "#{current_dir}/images/#{static_name}" end end
and in your View module, create the link like this:
img :src => R(StaticImage, 'logo.png')

Shake and bake for any kind of static resource you want to send.

The system of use is the repository


In the beginning, Web search was based on aspects of the resources being indexed, like term frequency and inverse document frequency. That's of course still important but things really took off when search engines started to treat the Web as a connected graph, placing as much importance on the interconnectedness of the resources as what was in the resources themselves. Google made a huge jump forward in this area with its PageRank algorithm.

As things stand, search for digital material for teaching and learning (or learning objects or open educational resources) focuses on the resources themselves (or metadata about them), just as early search engines did. These resources are usually stored separately from the systems in which they are used, in disconnected repositories.

Erik Duval and his team are doing some interesting work in this area with what they call attention metadata. It's a good start, but until we do away with repository silos and start using the system of use as the repository, this area of search will move slowly. If this is done, there will be all sorts of other information to use in heuristics to optimise results.

Indenting your code


In HTML whitespace is not treated as significant, and therefore it gets collapsed. This is a problem when you want to publish code because your indenting will disappear. The most common way around this is to wrap code in a pre element, but that looks like crap because it's always the default monospace font, and you can't style it. A better way is to use CSS, specifically white-space: pre;.

In WordPress, log in to the admin section, click Presentation and select Theme Editor. Choose Stylesheet from the list on the right, then look for the code declaration. Add white-space: pre; and you're done. Now, whenever you want to display code, wrap it in a code element.

Corrupt countries were more likely to support the OOXML document format | EFFI.org


During the voting process the reputation of ISO as a dependable technical standardization organization was questioned. For example, in Sweden a Microsoft representative was caught offering to recompense partners for voting yes to OOXML. Also a sudden interest from countries like Ivory Coast to the OOXML issue has been found suspicious.We studied the relation between the corruption level and voting behaviours of the countries. We found that more corrupted the country is, the more likely it was to vote for the unreserved acceptance of the OOXML standard proposal.

WordPress AtomPub FAQ


I've posted a small WordPress AtomPub FAQ. It's a temporary home until I can find somewhere sensible to put it. If you have anything you'd like to add or correct or mock, comment here. If you can offer a sensible place to put it, let me know.

Alternative PHP syntax for control structures


Reading through the WordPress source, I found some syntax I didn't recognize.
if ( !function_exists('wp_set_current_user') ) : function wp_set_current_user($id, $name = '') { global $current_user; if ( isset($current_user) && ($id == $current_user->ID) ) return $current_user; $current_user = new WP_User($id, $name); return $current_user; } endif;
A hunt revealed that this was an example of PHP's alternative syntax for control structures. You can replace an opening brace with a colon on some control structures, the closing brace with an end*;, where * is the control structure, and have blocks of multiple lines. Why would one use this? One example in the WordPress is a conditional function definition, which, okay, that's unusual, so maybe the unusual syntax makes it stand out, but in general I think using this is a terrible idea.