OpenID

I figured this new shiny OpenID thing was cool enough to start using it. There's just this one problem: I didn't want to have to go through the "register on a website and remember yet another password" dance once more; and since I have this marvellous Kerberos realm set up which works for authenticating against my webserver, too, why not use that?

So I downloaded the JanRain PHP OpenID library, and went hacking. It's not all that hard, really:

diff -ruN ./lib/actions.php /svr/www/openid.grep.be/data/lib/actions.php
--- ./lib/actions.php	2006-12-08 23:56:22.000000000 +0100
+++ /svr/www/openid.grep.be/data/lib/actions.php	2007-03-08 14:18:32.000000000 +0100
@@ -88,17 +88,24 @@
     if (!isset($input['openid_url'])) {
         $errors[] = 'Enter an OpenID URL to continue';
     }
-    if (!isset($input['password'])) {
-        $errors[] = 'Enter a password to continue';
+    if (!isset($input['password']) && !isset($_SERVER["REMOTE_USER"])) {
+        $errors[] = 'Enter a password to continue, or log in using an ' .
+			'apache logon method';
     }
     if (count($errors) == 0) {
         $openid_url = $input['openid_url'];
         $openid_url = Auth_OpenID::normalizeUrl($openid_url);
-        $password = $input['password'];
-        if (!checkLogin($openid_url, $password)) {
-            $errors[] = 'The entered password does not match the ' .
-                'entered identity URL.';
-        }
+	if(isset($_SERVER["REMOTE_USER"])) {
+	    if(!checkUser($openid_url, $_SERVER["REMOTE_USER"])) {
+	       $errors[] = 'The apache user does not match the openid URL';
+	    }
+	} else {
+           $password = $input['password'];
+           if (!checkLogin($openid_url, $password)) {
+               $errors[] = 'The entered password does not match the ' .
+                   'entered identity URL.';
+           }
+	}
     }
     return array($errors, $openid_url);
 }
@@ -166,4 +173,4 @@
     return sites_render($sites);
 }
 
-?>
\ No newline at end of file
+?>
diff -ruN ./lib/render/login.php /svr/www/openid.grep.be/data/lib/render/login.php
--- ./lib/render/login.php	2006-12-08 23:56:22.000000000 +0100
+++ /svr/www/openid.grep.be/data/lib/render/login.php	2007-03-08 14:53:56.000000000 +0100
@@ -3,6 +3,7 @@
 require_once "lib/session.php";
 require_once "lib/render.php";
 
+if(!isset($_SERVER["REMOTE_USER"])) {
 define('login_form_pat',
        '<div class="form">
   <p>
@@ -31,6 +32,33 @@
   </form>
 </div>
 ');
+} else {
+define('login_form_pat',
+       '<div class="form">
+  <p>
+    Enter your identity URL into this form to log in to this server. This
+    server must be configured to accept your identity URL. Since you already
+    logged on through an Apache method, entering a password is not required
+  </p>
+
+  <form method="post" action="%s">
+    <table>
+      <tr>
+        <th><label for="openid_url">OpenID URL:</label></th>
+        <td><input type="text" name="openid_url"
+                   value="%s" id="openid_url" /></td>
+      </tr>
+      <tr>
+        <td colspan="2">
+          <input type="submit" value="Log in" />
+          <input type="submit" name="cancel" value="Cancel" />
+        </td>
+      </tr>
+    </table>
+  </form>
+</div>
+');
+}
 
 define('login_needed_pat',
        'You must be logged in as %s to approve this request.');
@@ -62,4 +90,4 @@
     }
     return sprintf("<ul class=\"error\">\n%s</ul>\n", $text);
 }
-?>
\ No newline at end of file
+?>
diff -ruN ./lib/session.php /svr/www/openid.grep.be/data/lib/session.php
--- ./lib/session.php	2006-12-08 23:56:22.000000000 +0100
+++ /svr/www/openid.grep.be/data/lib/session.php	2007-03-08 14:34:49.000000000 +0100
@@ -129,6 +129,16 @@
 }
 
 /**
+ * Check whether the logged-on user matches the specified OpenID URL
+ */ 
+function checkUser($openid_url, $user)
+{
+    global $openid_user_urls;
+    return isset($openid_user_urls[$openid_url])
+        && $user = $openid_user_urls[$openid_url];
+}
+
+/**
  * Get the openid_url out of the cookie
  *
  * @return mixed $openid_url The URL that was stored in the cookie or
@@ -202,4 +212,4 @@
 
 }
 
-?>
\ No newline at end of file
+?>

It expects an array in config.php like so:

openid_user_urls = array(
	"http://wo.uter.be/" => "wouter@GREP.BE"
);

(in the case of kerberos; if you use a different authentication method, the syntax of that array will most likely be different, too)

It's still not perfect; all my changes really do is bypass the password check if it notices that apache has already authenticated the remote user; but I still need to "log on" at the PHP level, which also requires me to enter my OpenID URL. A somewhat cooler implementation would pre-enter the OpenID URL in the form. A really cool implementation would not even show me the logon form, but go straight to the "logged on" state, using the OpenID URL as given by the consumer, and the information apache provides us on the remote user. But it's a start.

Adding OpenID capabilities to my blog comment entry script is proving slightly more challenging, however. More on that later.