#! /usr/bin/perl # CorvID is a script to interface Raven to OpenID. # To use it, do something like: # # # # To install it, you'll need CGI, Ucam::WebAuth::CGIAA, and # Net::OpenID::Server. # # Handling of failure cases is somewhere between poor and nonexistent. # In particular, in checkid_immediate mode, we should respond to a # failure by returning a proper Raven login URL that will bounce back # to the calling site. use CGI; use Ucam::WebAuth::CGIAA; use Net::OpenID::Server; $keydir = "/u2/bjharris/corvid/webauth_keys"; $randomfile = "/u2/bjharris/corvid/random"; $realhostname = "bjh21.me.uk"; $query = new CGI; %aaargs = (hostname => $realhostname, key_dir => $keydir, do_session => 0); if ($query->param("WLS-Response")) { $aa = new Ucam::WebAuth::CGIAA(%aaargs); $aa->authenticate(); ($qs) = $aa->url =~ /\?(.*)$/; if ($qs) { warn "reloading CGI with params '$qs'\n"; $query = new CGI($qs); } } my $nos = new Net::OpenID::Server(get_args => $query, post_args => $query, get_user => \&get_user, is_identity => \&is_identity, is_trusted => \&is_trusted, server_secret => `cat $randomfile`); (($type, $resp) = $nos->handle_page) || die $nos->err; if ($type eq "redirect") { print "Location: $resp\n\n"; } elsif ($type eq "setup") { print "Content-type: text/plain\n\nsetup requested\n"; } else { print "Content-type: $type\n\n$resp"; } sub get_user { unless ($aacomplete) { $tr = $nos->args('openid.trust_root'); $aa = new Ucam::WebAuth::CGIAA(%aaargs, description => "OpenID proxy on behalf of $tr", cookie_name => "OpenID-Proxy-$tr-Session", do_session => 0); if ($nos->args('openid.mode') eq 'checkid_setup') { $aacomplete = $aa->authenticate(); $aacomplete || exit 0; unless ($aa->success) { if ($aa->status =~ /^4\d\d$/) { # Convert 4xx failure into a "cancel" response. print "Location: ", $nos->cancel_return_url(return_to => $nos->args('openid.return_to')), "\n\n"; exit 0; } else { my($msg) = CGI::escapeHTML($aa->msg); my($status) = CGI::escapeHTML($aa->status); print "Content-type: text/html; charset=us-ascii\n\n"; print qq[\n]; print qq[Authentication failed\n]; print qq[

Authentication failed

\n]; print qq[Raven gave the following error:\n]; print qq[
$msg
\n]; print qq[(error code $status)\n]; exit 0; } } } elsif ($nos->args('openid.mode') eq 'checkid_immediate') { $aacomplete = $aa->authenticate( interact => 'no'); $aacomplete || exit 0; unless ($aa->success) { # XXX We need to generate a URL that will retry this # authentication, I think. $nos->setup_url('about:blank'); } } } return $aa->success ? $aa->principal : undef; } sub is_identity { my ($u, $identity_url) = @_; warn "user = $u; url = $identity_url\n"; if (defined($u) && $identity_url =~ m!^tag:bjh21.me.uk,2007:corvid:\Q$u\E/?$!) { return 1; } unless ($nos->args('openid.mode') eq 'checkid_setup') { return 0; } $u = CGI::escapeHTML($u); $identity_url = CGI::escapeHTML($identity_url); print "Content-type: text/html; charset=us-ascii\n\n"; print qq[\n]; print qq[Authentication failed\n]; print qq[

Authentication failed

\n]; print qq[Your Raven user ID, $u, does not match\n]; print qq[the OpenID, $identity_url, that you tried\n]; print qq[to verify.\n]; exit 0; } sub is_trusted { return 1; }