* Add openidsignup config option.
[ikiwiki.git] / IkiWiki / Plugin / openid.pm
1 #!/usr/bin/perl
2 # OpenID support.
3 package IkiWiki::Plugin::openid;
4
5 use warnings;
6 use strict;
7 use IkiWiki;
8
9 sub import { #{{{
10         hook(type => "getopt", id => "openid", call => \&getopt);
11         hook(type => "checkconfig", id => "openid", call => \&checkconfig);
12         hook(type => "auth", id => "openid", call => \&auth);
13 } # }}}
14
15 sub getopt () { #{{{
16         eval q{use Getopt::Long};
17         error($@) if $@;
18         Getopt::Long::Configure('pass_through');
19         GetOptions("openidsignup=s" => \$config{openidsignup});
20 } #}}}
21
22 sub checkconfig () { #{{{
23         # Currently part of the OpenID code is in CGI.pm, and is enabled by
24         # this setting.
25         # TODO: modularise it all out into this plugin..
26         $config{openid}=1;
27 } #}}}
28
29 sub auth ($$) { #{{{
30         my $q=shift;
31         my $session=shift;
32
33         if (defined $q->param('openid.mode')) {
34                 my $csr=getobj($q, $session);
35
36                 if (my $setup_url = $csr->user_setup_url) {
37                         IkiWiki::redirect($q, $setup_url);
38                 }
39                 elsif ($csr->user_cancel) {
40                         IkiWiki::redirect($q, $config{url});
41                 }
42                 elsif (my $vident = $csr->verified_identity) {
43                         $session->param(name => $vident->url);
44                 }
45                 else {
46                         error("OpenID failure: ".$csr->err);
47                 }
48         }
49         elsif (defined $q->param('openid_identifier')) {
50                 validate($q, $session, $q->param('openid_identifier'));
51         }
52 } #}}}
53
54 sub validate ($$$;$) { #{{{
55         my $q=shift;
56         my $session=shift;
57         my $openid_url=shift;
58         my $form=shift;
59
60         my $csr=getobj($q, $session);
61
62         my $claimed_identity = $csr->claimed_identity($openid_url);
63         if (! $claimed_identity) {
64                 if ($form) {
65                         # Put the error in the form and fail validation.
66                         $form->field(name => "openid_url", comment => $csr->err);
67                         return 0;
68                 }
69                 else {
70                         error($csr->err);
71                 }
72         }
73
74         my $check_url = $claimed_identity->check_url(
75                 return_to => IkiWiki::cgiurl(do => "postsignin"),
76                 trust_root => $config{cgiurl},
77                 delayed_return => 1,
78         );
79         # Redirect the user to the OpenID server, which will
80         # eventually bounce them back to auth() above.
81         IkiWiki::redirect($q, $check_url);
82         exit 0;
83 } #}}}
84
85 sub getobj ($$) { #{{{
86         my $q=shift;
87         my $session=shift;
88
89         eval q{use Net::OpenID::Consumer};
90         error($@) if $@;
91
92         my $ua;
93         eval q{use LWPx::ParanoidAgent};
94         if (! $@) {
95                 $ua=LWPx::ParanoidAgent->new;
96         }
97         else {
98                 $ua=LWP::UserAgent->new;
99         }
100
101         # Store the secret in the session.
102         my $secret=$session->param("openid_secret");
103         if (! defined $secret) {
104                 $secret=$session->param(openid_secret => time);
105         }
106
107         return Net::OpenID::Consumer->new(
108                 ua => $ua,
109                 args => $q,
110                 consumer_secret => $secret,
111                 required_root => $config{cgiurl},
112         );
113 } #}}}
114
115 1