Wednesday, 10 October 2007

OpenID IdP for Cosign

I've been following OpenID's progress for a while - whilst there still aren't any "killer" applications making use of it, it is a very promising example of federated identity for the 'real' world. One of the potentials of running an internal authentication system is to use that to bootstrap an OpenID based on, so that whilst you're logged in to your organisation's system you can make use of an OpenID without requiring any additional authentication steps.

I spent a bit of time yesterday looking at the OpenID servers which are currently available. There isn't a huge amount of freely available server code - the easiest to modify appeared to be JanRain's PHP server, which is built on top of their general purpose PHP OpenID library. This server supports OpenID authentication, along with XRDS (a method for performing attribute exchange with OpenID enabled applications). However, it's designed to use an internal password database.

I've produced some patches to add a number of new features, allowing fallback against an enterprise authentication scheme.

  • When the ENTERPRISE_AUTHENTICATION define is set, if the web server provides a REMOTE_USER variable and the user exists in the local database, authenticate the user.
  • When the ENTERPRISE_AUTHENTICATION define is set, if REMOTE_USER is not set, remove any cached authentication information
  • When the AUTOMATIC_REGISTRATION define is set, and a REMOTE_USER doesn't exist in the local database, add them
  • When the login page is called, but a user has already logged in, just pass them on to the next stored action.

The patch is available from

The problem with this server is that it is all implemented through a single script. It isn't immediately apparent from the script which actions are expected to require authentication, and which are not. So, the scripts existing workflow is preserved. Cosign (our web authentication solution of choice) is configured so that it will provide REMOTE_USER information to the script where that is available, but won't prompt the user where it is not. This means that those portions of the script which should work for unauthenticated users will continue to do so, whilst those which require authentication redirect to the script's
?action=login handler. Secondly, Apache is configured using mod_rewrite so that requests for ?action=login are redirected to a Cosign protected location which always requires authentication. This triggers the usual Cosign authentication process, which eventually redirects back to the script itself. The change to the login page to accept pre-authenticated users then kicks in, and the script continues processing as usual.

The Apache configuration magic that accomplishes all of this is as follows:

Alias /iVouch/ /var/www/openid/src/
Alias /iVouch-login/ /var/www/openid/src/
php_value session.save_path /var/openid-session/

<Location /iVouch-login>
CosignProtected On
CosignGetKerberosTickets On

<Location /iVouch>
CosignProtected On
CosignAllowPublicAccess On

RewriteEngine On
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{LA-U:REMOTE_USER} ^$
RewriteRule ^/iVouch/$ /iVouch-login/ [PT]

RewriteCond %{QUERY_STRING} action=login
RewriteRule ^/iVouch/$ /iVouch-login/ [PT]

RewriteCond %{QUERY_STRING} action=logout
RewriteRule ^/iVouch/$ [R]

This all assumes that the OpenID server is sitting under /iVouch/ on the web server - we'll probably move this to the top level if it ever goes into production. The first set of rewrite rules mean that if you go to the front page of the script you will get logged in. The second set of rules force a login when the scripts login action is performed. The third rule calls the central cosign logout function when the scripts logout action is reached.

No comments: