aboutsummaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/loginselector.pm
blob: 17539ce8afe33fc9896803fe56a88d36a04bc0d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/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, an error
	# display callback, and an info 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());
			}, sub {
				$template->param(login_info => 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);
	hook(type => "auth", id => "loginselector", call => \&authstub);
}

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) {
			# Special case to avoid labeling password auth as
			# "Other" when it's the only auth plugin not
			# integrated with the loginselector.
			my %h=%{$IkiWiki::hooks{auth}};
			foreach my $p (keys %login_plugins) {
				delete $h{$p};
			}
			delete $h{loginselector};
			if (keys %h == 1 && exists $h{passwordauth}) {
				$otherform_label=gettext("Password");
			}
			if (keys %h > 0) {
				$real_cgi_signin=\&IkiWiki::cgi_signin;
			}
		}
		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,
		},
}

sub authstub ($$) {
	# While this hook is not currently used, it needs to exist
	# so ikiwiki knows that the wiki supports logins, and will
	# enable the Preferences page.
}

1