--- /dev/null
+#!/usr/bin/perl
+package IkiWiki::Plugin::loginselector;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+# Plugins that provide login methods can register themselves here.
+# Note that the template and js file also have be be modifed to add a new
+# login method.
+our %login_plugins;
+
+sub register_login_plugin ($$$$) {
+ # Same as the name of the plugin that is registering itself as a
+ # login plugin. eg, "openid"
+ my $plugin_name=shift;
+ # This sub is passed a cgi object and a template object which it
+ # can manipulate. It should return true if the plugin can be used
+ # (it might load necessary modules for auth checking, for example).
+ my $plugin_setup=shift;
+ # This sub is passed a cgi object, and should return true
+ # if it looks like the user is logging in using the plugin.
+ my $plugin_check_input=shift;
+ # This sub is passed a cgi object, a session object, and an error
+ # display callback, and should handle the actual authentication.
+ # It can either exit w/o returning, if it is able to handle
+ # auth, or it can pass an error message to the error display
+ # callback to make the openid selector form be re-disiplayed with
+ # an error message on it.
+ my $plugin_auth=shift;
+ $login_plugins{$plugin_name}={
+ setup => $plugin_setup,
+ check_input => $plugin_check_input,
+ auth => $plugin_auth,
+ };
+}
+
+sub login_selector {
+ my $real_cgi_signin=shift;
+ my $otherform_label=shift;
+ my $q=shift;
+ my $session=shift;
+
+ my $template=IkiWiki::template("login-selector.tmpl");
+
+ foreach my $plugin (keys %login_plugins) {
+ if (! $login_plugins{$plugin}->{setup}->($template)) {
+ delete $login_plugins{$plugin};
+ }
+ else {
+ $template->param("login_selector_$plugin", 1);
+ }
+ }
+
+ foreach my $plugin (keys %login_plugins) {
+ if ($login_plugins{$plugin}->{check_input}->($q)) {
+ $login_plugins{$plugin}->{auth}->($q, $session, sub {
+ $template->param(login_error => shift());
+ });
+ last;
+ }
+ }
+
+ $template->param(
+ cgiurl => IkiWiki::cgiurl(),
+ ($real_cgi_signin ? (otherform => $real_cgi_signin->($q, $session, 1)) : ()),
+ otherform_label => $otherform_label,
+ );
+
+ IkiWiki::printheader($session);
+ print IkiWiki::cgitemplate($q, "signin", $template->output);
+ exit;
+}
+
+sub import {
+ add_underlay("login-selector");
+ add_underlay("jquery");
+ hook(type => "getsetup", id => "loginselector", call => \&getsetup);
+ hook(type => "checkconfig", id => "loginselector", call => \&checkconfig);
+}
+
+sub checkconfig () {
+ if ($config{cgi}) {
+ # Intercept normal signin form, so the login 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;
+ my $otherform_label=gettext("Other");
+ if (keys %{$IkiWiki::hooks{auth}} > 1) {
+ $real_cgi_signin=\&IkiWiki::cgi_signin;
+ my %h=%{$IkiWiki::hooks{auth}};
+ foreach my $p (keys %login_plugins) {
+ delete $h{$p};
+ }
+ # Special case to avoid labeling password auth as
+ # "Other" when it's the only auth plugin not
+ # integrated with the loginselector.
+ if (keys %h == 1 && exists $h{passwordauth}) {
+ $otherform_label=gettext("Password");
+ }
+ }
+ inject(name => "IkiWiki::cgi_signin", call => sub ($$) {
+ login_selector($real_cgi_signin, $otherform_label, @_);
+ });
+ }
+}
+
+sub getsetup () {
+ return
+ plugin => {
+ # this plugin is safe but only makes sense as a
+ # dependency
+ safe => 0,
+ rebuild => 0,
+ },
+}
+
+1
use IkiWiki 3.00;
sub import {
- add_underlay("login-selector");
- add_underlay("jquery");
- hook(type => "checkconfig", id => "openid", call => \&checkconfig);
hook(type => "getsetup", id => "openid", call => \&getsetup);
hook(type => "auth", id => "openid", call => \&auth);
hook(type => "formbuilder_setup", id => "openid",
call => \&formbuilder_setup, last => 1);
-}
-
-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;
- my $otherform_label=gettext("Other");
- if (keys %{$IkiWiki::hooks{auth}} > 1) {
- $real_cgi_signin=\&IkiWiki::cgi_signin;
- my %h=%{$IkiWiki::hooks{auth}};
- delete $h{openid};
- delete $h{emailauth};
- if (keys %h == 1 && exists $h{passwordauth}) {
- $otherform_label=gettext("Password");
- }
- }
- inject(name => "IkiWiki::cgi_signin", call => sub ($$) {
- openid_selector($real_cgi_signin, $otherform_label, @_);
- });
- }
+ IkiWiki::loadplugin("loginselector");
+ IkiWiki::Plugin::loginselector::register_login_plugin(
+ "openid",
+ \&openid_setup,
+ \&openid_check_input,
+ \&openid_auth,
+ );
}
sub getsetup () {
},
}
-sub openid_selector {
- my $real_cgi_signin=shift;
- my $otherform_label=shift;
- my $q=shift;
- my $session=shift;
-
- my $template=IkiWiki::template("login-selector.tmpl");
- my $openid_url=$q->param('openid_identifier');
+sub openid_setup ($$) {
+ my $q=shift;
+ my $template=shift;
- if (! load_openid_module()) {
- if ($real_cgi_signin) {
- $real_cgi_signin->($q, $session);
- exit;
+ if (load_openid_module()) {
+ my $openid_url=$q->param('openid_identifier');
+ if (defined $openid_url) {
+ $template->param(openid_url => $openid_url);
}
- error(sprintf(gettext("failed to load openid module: "), @_));
+ return 1;
}
- elsif (defined $q->param("action") && $q->param("action") eq "verify" && defined $openid_url && length $openid_url) {
- validate($q, $session, $openid_url, sub {
- $template->param(login_error => shift())
- });
+ else {
+ return 0;
}
+}
- $template->param(
- cgiurl => IkiWiki::cgiurl(),
- (defined $openid_url ? (openid_url => $openid_url) : ()),
- ($real_cgi_signin ? (otherform => $real_cgi_signin->($q, $session, 1)) : ()),
- otherform_label => $otherform_label,
- login_selector_openid => 1,
- login_selector_email => 1,
- );
+sub openid_check_input ($) {
+ my $q=shift;
+ my $openid_url=$q->param('openid_identifier');
+ defined $q->param("action") && $q->param("action") eq "verify" && defined $openid_url && length $openid_url;
+}
- IkiWiki::printheader($session);
- print IkiWiki::cgitemplate($q, "signin", $template->output);
- exit;
+sub openid_auth ($$$) {
+ my $q=shift;
+ my $session=shift;
+ my $errordisplayer=shift;
+ my $openid_url=$q->param('openid_identifier');
+ validate($q, $session, $openid_url, $errordisplayer);
}
sub formbuilder_setup (@) {
* When openid and passwordauth are the only enabled auth plugins,
make the openid selector display "Password" instead of "Other",
so users are more likely to click on it when they don't have an openid.
+ * Converted openid-selector into a more generic loginselector helper
+ plugin.
-- Joey Hess <id@joeyh.name> Tue, 28 Apr 2015 12:24:08 -0400
if the name is set to the name of a user who is not registered,
a basic registration of the user will be automatically performed.
+Auth plugins can use the loginselector helper plugin to let the user
+select which authentication method to use.
+
### <a name="sessioncgi">sessioncgi</a>
hook(type => "sessioncgi", id => "foo", call => \&sessioncgi);
'openid_identifier',
{
<TMPL_IF LOGIN_SELECTOR_OPENID>'openid': 1,</TMPL_IF>
- <TMPL_IF LOGIN_SELECTOR_EMAIL>'email': 1,</TMPL_IF>
+ <TMPL_IF LOGIN_SELECTOR_EMAILAUTH>'email': 1,</TMPL_IF>
},
'<TMPL_IF OTHERFORM>otherform</TMPL_IF>',
'<TMPL_VAR OTHERFORM_LABEL>'
</div>
<div id="login_input_area">
- <div>
- <h3>OpenId login:</h3>
<TMPL_IF LOGIN_SELECTOR_OPENID>
- <label for="openid_identifier" class="block">Enter your OpenID:</label>
- <input id="openid_identifier" name="openid_identifier" type="text" value="<TMPL_VAR ESCAPE=HTML OPENID_URL>"/>
- <input id="openid_submit" type="submit" value="Login"/>
+ <div>
+ <h3>OpenId login:</h3>
+ <label for="openid_identifier" class="block">Enter your OpenID:</label>
+ <input id="openid_identifier" name="openid_identifier" type="text" value="<TMPL_VAR ESCAPE=HTML OPENID_URL>"/>
+ <input id="openid_submit" type="submit" value="Login"/>
+ </div>
</TMPL_IF>
- </div>
- <div>
- <h3>Email login:</h3>
- <TMPL_IF LOGIN_SELECTOR_EMAIL>
- <label for="email_address" class="block">Enter your email address:</label>
- <input id="email_address" name="Email_entry" type="text" value="<TMPL_VAR ESCAPE=HTML EMAIL_ADDRESS>"/>
- <input id="email_submit" type="submit" value="Login"/>
+ <TMPL_IF LOGIN_SELECTOR_EMAILAUTH>
+ <div>
+ <h3>Email login:</h3>
+ <label for="email_address" class="block">Enter your email address:</label>
+ <input id="email_address" name="Email_entry" type="text" value="<TMPL_VAR ESCAPE=HTML EMAIL_ADDRESS>"/>
+ <input id="email_submit" type="submit" value="Login"/>
+ </div>
</TMPL_IF>
</div>
- </div>
<TMPL_IF LOGIN_ERROR>
<div class="error"><TMPL_VAR LOGIN_ERROR></div>