summaryrefslogtreecommitdiff
path: root/IkiWiki
diff options
context:
space:
mode:
Diffstat (limited to 'IkiWiki')
-rw-r--r--IkiWiki/CGI.pm77
-rw-r--r--IkiWiki/Plugin/httpauth.pm22
-rw-r--r--IkiWiki/Plugin/openid.pm101
-rw-r--r--IkiWiki/Plugin/skeleton.pm8
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");
} #}}}