X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/378c64776856ee1313c030375a921e8acb4ff1ef..1d46ebef52412b3b93e547ce124d813cf34e3b56:/IkiWiki/Plugin/openid.pm diff --git a/IkiWiki/Plugin/openid.pm b/IkiWiki/Plugin/openid.pm index 0ad8697d8..b6642619a 100644 --- a/IkiWiki/Plugin/openid.pm +++ b/IkiWiki/Plugin/openid.pm @@ -7,8 +7,9 @@ use strict; use IkiWiki 3.00; sub import { + add_underlay("openid-selector"); + add_underlay("jquery"); hook(type => "checkconfig", id => "openid", call => \&checkconfig); - hook(type => "getopt", id => "openid", call => \&getopt); hook(type => "getsetup", id => "openid", call => \&getsetup); hook(type => "auth", id => "openid", call => \&auth); hook(type => "formbuilder_setup", id => "openid", @@ -19,21 +20,20 @@ sub checkconfig () { if ($config{cgi}) { # Intercept normal signin form, so the openid selector # can be displayed. + # + # When other auth hooks are registered, give the selector + # a reference to the normal signin form. require IkiWiki::CGI; - my $real_cgi_signin=\&IkiWiki::cgi_signin; + my $real_cgi_signin; + if (keys %{$IkiWiki::hooks{auth}} > 1) { + $real_cgi_signin=\&IkiWiki::cgi_signin; + } inject(name => "IkiWiki::cgi_signin", call => sub ($$) { - openid_selector($real_cgi_signin, @_); + openid_selector($real_cgi_signin, @_); }); } } -sub getopt () { - eval q{use Getopt::Long}; - error($@) if $@; - Getopt::Long::Configure('pass_through'); - GetOptions("openidsignup=s" => \$config{openidsignup}); -} - sub getsetup () { return plugin => { @@ -41,11 +41,16 @@ sub getsetup () { rebuild => 0, section => "auth", }, - openidsignup => { + openid_realm => { type => "string", - example => "http://myopenid.com/", - description => "an url where users can signup for an OpenID", - safe => 1, + description => "url pattern of openid realm (default is cgiurl)", + safe => 0, + rebuild => 0, + }, + openid_cgiurl => { + type => "string", + description => "url to ikiwiki cgi to use for openid authentication (default is cgiurl)", + safe => 0, rebuild => 0, }, } @@ -55,31 +60,32 @@ sub openid_selector { my $q=shift; my $session=shift; - my $openid_url=$q->param('openid_url'); + my $openid_url=$q->param('openid_identifier'); my $openid_error; - if (defined $q->param("action") && $q->param("action") eq "verify") { + if (! load_openid_module()) { + if ($real_cgi_signin) { + $real_cgi_signin->($q, $session); + exit; + } + error(sprintf(gettext("failed to load openid module: "), @_)); + } + elsif (defined $q->param("action") && $q->param("action") eq "verify") { validate($q, $session, $openid_url, sub { $openid_error=shift; }); } - elsif ($q->param("do") eq "signin" || ! load_openid_module()) { - $real_cgi_signin->($q, $session); - exit; - } my $template=IkiWiki::template("openid-selector.tmpl"); $template->param( - cgiurl => $config{cgiurl}, + cgiurl => IkiWiki::cgiurl(), (defined $openid_error ? (openid_error => $openid_error) : ()), (defined $openid_url ? (openid_url => $openid_url) : ()), - # TODO only if other auth methods are available - nonopenidurl => IkiWiki::cgiurl(do => "signin"), - loginlabel => loginlabel(), + ($real_cgi_signin ? (nonopenidform => $real_cgi_signin->($q, $session, 1)) : ()), ); IkiWiki::printheader($session); - print IkiWiki::misctemplate("signin", $template->output); + print IkiWiki::cgitemplate($q, "signin", $template->output); exit; } @@ -90,48 +96,12 @@ sub formbuilder_setup (@) { my $session=$params{session}; my $cgi=$params{cgi}; - if ($form->title eq "signin") { - return unless load_openid_module(); - - # This avoids it displaying a redundant label for the - # OpenID fieldset. - $form->fieldsets("OpenID"); - - $form->field( - name => "openid_url", - label => loginlabel(), - fieldset => "OpenID", - size => 30, - comment => ($config{openidsignup} ? " | ".gettext("Get an OpenID")."" : "") - ); - - # Handle submission of an OpenID as validation. - if ($form->submitted && $form->submitted eq "Login" && - defined $form->field("openid_url") && - length $form->field("openid_url")) { - $form->field( - name => "openid_url", - validate => sub { - validate($cgi, $session, shift, sub { - # Display error in the form. - $form->field(name => "openid_url", comment => shift); - }); - }, - ); - # Skip all other required fields in this case. - foreach my $field ($form->field) { - next if $field eq "openid_url"; - $form->field(name => $field, required => 0, - validate => '/.*/'); - } - } - } - elsif ($form->title eq "preferences" && + if ($form->title eq "preferences" && IkiWiki::openiduser($session->param("name"))) { - $form->field(name => "openid_url", disabled => 1, + $form->field(name => "openid_identifier", disabled => 1, label => htmllink("", "", "ikiwiki/OpenID", noimageinline => 1), value => $session->param("name"), - size => 50, force => 1, + size => length($session->param("name")), force => 1, fieldset => "login"); $form->field(name => "email", type => "hidden"); } @@ -178,9 +148,15 @@ sub validate ($$$;$) { ); } + my $cgiurl=$config{openid_cgiurl}; + $cgiurl=$q->url if ! defined $cgiurl; + + my $trust_root=$config{openid_realm}; + $trust_root=$cgiurl if ! defined $trust_root; + my $check_url = $claimed_identity->check_url( - return_to => IkiWiki::cgiurl(do => "postsignin"), - trust_root => $config{cgiurl}, + return_to => "$cgiurl?do=postsignin", + trust_root => $trust_root, delayed_return => 1, ); # Redirect the user to the OpenID server, which will @@ -200,7 +176,7 @@ sub auth ($$) { IkiWiki::redirect($q, $setup_url); } elsif ($csr->user_cancel) { - IkiWiki::redirect($q, $config{url}); + IkiWiki::redirect($q, IkiWiki::baseurl(undef)); } elsif (my $vident = $csr->verified_identity) { $session->param(name => $vident->url); @@ -212,12 +188,17 @@ sub auth ($$) { $vident->signed_extension_fields('http://openid.net/srv/ax/1.0'), ); } + my $nickname; foreach my $ext (@extensions) { foreach my $field (qw{value.email email}) { if (exists $ext->{$field} && defined $ext->{$field} && length $ext->{$field}) { $session->param(email => $ext->{$field}); + if (! defined $nickname && + $ext->{$field}=~/(.+)@.+/) { + $nickname = $1; + } last; } } @@ -225,11 +206,15 @@ sub auth ($$) { if (exists $ext->{$field} && defined $ext->{$field} && length $ext->{$field}) { - $session->param(username => $ext->{$field}); + $nickname=$ext->{$field}; last; } } } + if (defined $nickname) { + $session->param(nickname => + Encode::decode_utf8($nickname)); + } } else { error("OpenID failure: ".$csr->err); @@ -245,6 +230,7 @@ sub getobj ($$) { my $q=shift; my $session=shift; + eval q{use Net::INET6Glue::INET_is_INET6}; # may not be available eval q{use Net::OpenID::Consumer}; error($@) if $@; @@ -263,12 +249,15 @@ sub getobj ($$) { $secret=rand; $session->param(openid_secret => $secret); } + + my $cgiurl=$config{openid_cgiurl}; + $cgiurl=$q->url if ! defined $cgiurl; return Net::OpenID::Consumer->new( ua => $ua, args => $q, consumer_secret => sub { return shift()+$secret }, - required_root => $config{cgiurl}, + required_root => $cgiurl, ); } @@ -282,8 +271,4 @@ sub load_openid_module { return 1; } -sub loginlabel { - return gettext("Log in with")." ".htmllink("", "", "ikiwiki/OpenID", noimageinline => 1); -} - 1