diff options
author | joey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071> | 2006-11-20 01:52:18 +0000 |
---|---|---|
committer | joey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071> | 2006-11-20 01:52:18 +0000 |
commit | 54cf5a62cab254e923c8d73ae8bd043a1f33c3b1 (patch) | |
tree | bc30fa8f0ec7070eadb5dace8e9743272f742ba2 /IkiWiki | |
parent | ad01bcd8b49deed11f602c43d1da8235280d5d6b (diff) | |
download | ikiwiki-54cf5a62cab254e923c8d73ae8bd043a1f33c3b1.tar ikiwiki-54cf5a62cab254e923c8d73ae8bd043a1f33c3b1.tar.gz |
* Make auth methods pluggable.
* Move httpauth support to a plugin.
* Add an openid plugin to support logging in using OpenID.
Diffstat (limited to 'IkiWiki')
-rw-r--r-- | IkiWiki/CGI.pm | 77 | ||||
-rw-r--r-- | IkiWiki/Plugin/httpauth.pm | 22 | ||||
-rw-r--r-- | IkiWiki/Plugin/openid.pm | 101 | ||||
-rw-r--r-- | IkiWiki/Plugin/skeleton.pm | 8 |
4 files changed, 183 insertions, 25 deletions
diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index ce4b6ada1..def0549c5 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -120,7 +120,7 @@ sub cgi_signin ($$) { #{{{ error($@) if $@; my $form = CGI::FormBuilder->new( title => "signin", - fields => [qw(do title page subpage from name password)], + fields => [qw(do title page subpage from name password openid_url)], header => 1, charset => "utf-8", method => 'POST', @@ -149,32 +149,56 @@ sub cgi_signin ($$) { #{{{ $form->field(name => "from", type => "hidden"); $form->field(name => "subpage", type => "hidden"); $form->field(name => "password", type => "password", required => 0); + if ($config{openid}) { + $form->field(name => "openid_url", label => "OpenID", comment => "to log in via OpenID"); + } + else { + $form->field(name => "openid_url", type => "hidden"); + } if ($form->submitted eq "Register" || $form->submitted eq "Create Account") { $form->title("register"); $form->text(""); $form->fields(qw(do title page subpage from name password confirm_password email)); $form->field(name => "confirm_password", type => "password"); $form->field(name => "email", type => "text"); + $form->field(name => "openid_url", type => "hidden"); } if ($q->param("do") ne "signin" && !$form->submitted) { $form->text("You need to log in first."); } if ($form->submitted) { + my $submittype=$form->submitted; + # OpenID login uses the Login button, but validates + # differently. + if ($submittype eq "Login" && $config{openid} && + length $form->field("openid_url")) { + $submittype="OpenID"; + + $form->field( + name => "openid_url", + validate => sub { + # FIXME: ugh + IkiWiki::Plugin::openid::validate($q, $session, $form, shift); + }, + ); + } + # Set required fields based on how form was submitted. my %required=( "Login" => [qw(name password)], "Register" => [], "Create Account" => [qw(name password confirm_password email)], "Mail Password" => [qw(name)], + "OpenID" => [qw(openid_url)], ); - foreach my $opt (@{$required{$form->submitted}}) { + foreach my $opt (@{$required{$submittype}}) { $form->field(name => $opt, required => 1); } # Validate password differently depending on how # form was submitted. - if ($form->submitted eq 'Login') { + if ($submittype eq 'Login') { $form->field( name => "password", validate => sub { @@ -184,13 +208,13 @@ sub cgi_signin ($$) { #{{{ ); $form->field(name => "name", validate => '/^\w+$/'); } - else { + elsif ($submittype ne 'OpenID') { $form->field(name => "password", validate => 'VALUE'); } # And make sure the entered name exists when logging # in or sending email, and does not when registering. - if ($form->submitted eq 'Create Account' || - $form->submitted eq 'Register') { + if ($submittype eq 'Create Account' || + $submittype eq 'Register') { $form->field( name => "name", validate => sub { @@ -201,7 +225,7 @@ sub cgi_signin ($$) { #{{{ }, ); } - else { + elsif ($submittype ne 'OpenID') { $form->field( name => "name", validate => sub { @@ -229,8 +253,8 @@ sub cgi_signin ($$) { #{{{ do => $form->field("do"), page => $form->field("page"), title => $form->field("title"), - subpage => $form->field("subpage"), from => $form->field("from"), + subpage => $form->field("subpage"), )); } else { @@ -680,11 +704,30 @@ sub cgi () { #{{{ { FileName => "$config{wikistatedir}/sessions.db" }); umask($oldmask); + # Auth hooks can sign a user in. + if ($do ne 'signin' && ! defined $session->param("name")) { + run_hooks(auth => sub { + shift->($q, $session) + }); + if (defined $session->param("name")) { + # Make sure whatever user was authed is in the + # userinfo db. + if (! userinfo_get($session->param("name"), "regdate")) { + userinfo_setall($session->param("name"), { + email => "", + password => "", + regdate => time, + }); + } + } + } + # Everything below this point needs the user to be signed in. if (((! $config{anonok} || $do eq 'prefs') && (! $config{httpauth}) && (! defined $session->param("name") || - ! userinfo_get($session->param("name"), "regdate"))) || $do eq 'signin') { + ! userinfo_get($session->param("name"), "regdate"))) + || $do eq 'signin') { cgi_signin($q, $session); # Force session flush with safe umask. @@ -695,22 +738,6 @@ sub cgi () { #{{{ return; } - if ($config{httpauth} && (! defined $session->param("name"))) { - if (! defined $q->remote_user()) { - error("Could not determine authenticated username."); - } - else { - $session->param("name", $q->remote_user()); - if (! userinfo_get($session->param("name"), "regdate")) { - userinfo_setall($session->param("name"), { - email => "", - password => "", - regdate=>time, - }); - } - } - } - if (defined $session->param("name") && userinfo_get($session->param("name"), "banned")) { print $q->header(-status => "403 Forbidden"); $session->delete(); diff --git a/IkiWiki/Plugin/httpauth.pm b/IkiWiki/Plugin/httpauth.pm new file mode 100644 index 000000000..336eb793a --- /dev/null +++ b/IkiWiki/Plugin/httpauth.pm @@ -0,0 +1,22 @@ +#!/usr/bin/perl +# HTTP basic auth plugin. +package IkiWiki::Plugin::httpauth; + +use warnings; +use strict; +use IkiWiki; + +sub import { #{{{ + hook(type => "auth", id => "skeleton", call => \&auth); +} # }}} + +sub auth ($$) { #{{{ + my $cgi=shift; + my $session=shift; + + if (defined $cgi->remote_user()) { + $session->param("name", $cgi->remote_user()); + } +} #}}} + +1 diff --git a/IkiWiki/Plugin/openid.pm b/IkiWiki/Plugin/openid.pm new file mode 100644 index 000000000..55b1c4b17 --- /dev/null +++ b/IkiWiki/Plugin/openid.pm @@ -0,0 +1,101 @@ +#!/usr/bin/perl +# OpenID support. +package IkiWiki::Plugin::openid; + +use warnings; +use strict; +use IkiWiki; + +sub import { #{{{ + hook(type => "checkconfig", id => "smiley", call => \&checkconfig); + hook(type => "auth", id => "skeleton", call => \&auth); +} # }}} + +sub checkconfig () { #{{{ + # Currently part of the OpenID code is in CGI.pm, and is enabled by + # this setting. + # TODO: modularise it all out into this plugin.. + $config{openid}=1; +} #}}} + +sub auth ($$) { #{{{ + my $q=shift; + my $session=shift; + + if (defined $q->param('openid.mode')) { + my $csr=getobj($q, $session); + + if (my $setup_url = $csr->user_setup_url) { + IkiWiki::redirect($q, $setup_url); + } + elsif ($csr->user_cancel) { + IkiWiki::redirect($q, $config{url}); + } + elsif (my $vident = $csr->verified_identity) { + $session->param(name => $vident->url); + } + } +} #}}} + +sub validate ($$$$) { #{{{ + my $q=shift; + my $session=shift; + my $form=shift; + my $openid_url=shift; + + my $csr=getobj($q, $session); + + my $claimed_identity = $csr->claimed_identity($openid_url); + if (! $claimed_identity) { + # Put the error in the form and fail validation. + $form->field(name => "openid_url", comment => $csr->err); + return 0; + } + my $check_url = $claimed_identity->check_url( + return_to => IkiWiki::cgiurl( + do => $form->field("do"), + page => $form->field("page"), + title => $form->field("title"), + from => $form->field("from"), + subpage => $form->field("subpage") + ), + trust_root => $config{cgiurl}, + delayed_return => 1, + ); + # Redirect the user to the OpenID server, which will + # eventually bounce them back to auth() above. + IkiWiki::redirect($q, $check_url); + exit 0; +} #}}} + +sub getobj ($$) { #{{{ + my $q=shift; + my $session=shift; + + eval q{use Net::OpenID::Consumer}; + error($@) if $@; + + my $ua; + eval q{use LWPx::ParanoidAgent}; + if (! $@) { + $ua=LWPx::ParanoidAgent->new; + } + else { + $ua=LWP::UserAgent->new; + } + + # Store the secret in the session. + my $secret=$session->param("openid_secret"); + if (! defined $secret) { + $secret=$session->param(openid_secret => time); + } + + return Net::OpenID::Consumer->new( + ua => $ua, + args => $q, + consumer_secret => $secret, + required_root => $config{cgiurl}, + ); +} #}}} + +1 diff --git a/IkiWiki/Plugin/skeleton.pm b/IkiWiki/Plugin/skeleton.pm index acac16c1a..f3244ae14 100644 --- a/IkiWiki/Plugin/skeleton.pm +++ b/IkiWiki/Plugin/skeleton.pm @@ -20,6 +20,7 @@ sub import { #{{{ hook(type => "delete", id => "skeleton", call => \&delete); hook(type => "change", id => "skeleton", call => \&change); hook(type => "cgi", id => "skeleton", call => \&cgi); + hook(type => "auth", id => "skeleton", call => \&auth); hook(type => "savestate", id => "savestate", call => \&savestate); } # }}} @@ -95,6 +96,13 @@ sub cgi ($) { #{{{ debug("skeleton plugin running in cgi"); } #}}} +sub auth ($$) { #{{{ + my $cgi=shift; + my $session=shift; + + debug("skeleton plugin running in auth"); +} #}}} + sub savestate () { #{{{ debug("skeleton plugin running in savestate"); } #}}} |