]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blob - doc/plugins/contrib/unixauth.mdwn
patching Wrapper.pm no longer necessary as of 2.67
[git.ikiwiki.info.git] / doc / plugins / contrib / unixauth.mdwn
1 [[!template id=plugin name=unixauth core=0 author="[[schmonz]]"]]
2 [[!tag type/auth]]
4 This plugin authenticates users against the Unix user database. It presents a similar UI to [[plugins/passwordauth]], but simpler, as there's no need to be able to register or change one's password.
6 To authenticate, either [checkpassword](http://cr.yp.to/checkpwd.html) or [pwauth](http://www.unixpapa.com/pwauth/) must be installed and configured. `checkpassword` is strongly preferred. If your web server runs as an unprivileged user -- as it darn well should! -- then `checkpassword` needs to be setuid root. (Or your ikiwiki CGI wrapper, I guess, but don't do that.) Other checkpassword implementations are available, notably [checkpassword-pam](http://checkpasswd-pam.sourceforge.net/).
8 Config variables that affect the behavior of `unixauth`:
10 * `unixauth_type`: defaults to unset, can be "checkpassword" or "pwauth"
11 * `unixauth_command`: defaults to unset, should contain the full path and any arguments
12 * `unixauth_requiressl`: defaults to 1, can be 0
13 * `sslcookie`: needs to be 1 if `unixauth_requiressl` is 1 (perhaps this should be done automatically?)
15 __Security__: [As with passwordauth](/security/#index14h2), be wary of sending usernames and passwords in cleartext. Unlike passwordauth, sniffing `unixauth` credentials can get an attacker much further than mere wiki access. Therefore, this plugin defaults to not even _displaying_ the login form fields unless we're running under SSL. Nobody should be able to do anything remotely dumb until the admin has done at least a little thinking. After that, dumb things are always possible. ;-)
17 `unixauth` needs the `HTTPS` environment variable, available in ikiwiki 2.67 or later (fixed in #[502047](http://bugs.debian.org/502047)), without which it fails closed.
19 The plugin has not been tested with newer versions of ikiwiki. [[schmonz]] hopes to have time to polish this plugin soon.
21 [[!toggle id="code" text="unixauth.pm"]]
23 [[!toggleable id="code" text="""
25     #!/usr/bin/perl
26     # Ikiwiki unixauth authentication.
27     package IkiWiki::Plugin::unixauth;
28     
29     use warnings;
30     use strict;
31     use IkiWiki 2.00;
32     
33     sub import {
34         hook(type => "getsetup", id => "unixauth", call => \&getsetup);
35             hook(type => "formbuilder_setup", id => "unixauth",
36                 call => \&formbuilder_setup);
37             hook(type => "formbuilder", id => "unixauth",
38                 call => \&formbuilder);
39         hook(type => "sessioncgi", id => "unixauth", call => \&sessioncgi);
40     }
41     
42     sub getsetup () {
43         return
44         unixauth_type => {
45                 type => "string",
46                 example => "checkpassword",
47                 description => "type of authenticator; can be 'checkpassword' or 'pwauth'",
48                 safe => 0,
49                 rebuild => 1,
50         },
51         unixauth_command => {
52                 type => "string",
53                 example => "/path/to/checkpassword",
54                 description => "full path and any arguments",
55                 safe => 0,
56                 rebuild => 1,
57         },
58         unixauth_requiressl => {
59                 type => "boolean",
60                 example => "1",
61                 description => "require SSL? strongly recommended",
62                 safe => 0,
63                 rebuild => 1,
64         },
65         plugin => {
66                 description => "Unix user authentication",
67                 safe => 0,
68                 rebuild => 1,
69         },
70     }
71     
72     # Checks if a string matches a user's password, and returns true or false.
73     sub checkpassword ($$;$) {
74         my $user=shift;
75         my $password=shift;
76         my $field=shift || "password";
77     
78         # It's very important that the user not be allowed to log in with
79         # an empty password!
80         if (! length $password) {
81                 return 0;
82         }
83     
84         my $ret=0;
85         if (! exists $config{unixauth_type}) {
86                 # admin needs to carefully think over his configuration
87                 return 0;
88         }
89         elsif ($config{unixauth_type} eq "checkpassword") {
90                 open UNIXAUTH, "|$config{unixauth_command} true 3<&0" or die("Could not run $config{unixauth_type}");
91                 print UNIXAUTH "$user\0$password\0Y123456\0";
92                 close UNIXAUTH;
93                 $ret=!($?>>8);
94         }
95         elsif ($config{unixauth_type} eq "pwauth") {
96                 open UNIXAUTH, "|$config{unixauth_command}" or die("Could not run $config{unixauth_type}");
97                 print UNIXAUTH "$user\n$password\n";
98                 close UNIXAUTH;
99                 $ret=!($?>>8);
100         }
101         else {
102                 # no such authentication type
103                 return 0;
104         }
105     
106         if ($ret) {
107             my $userinfo=IkiWiki::userinfo_retrieve();
108             if (! length $user || ! defined $userinfo ||
109                 ! exists $userinfo->{$user} || ! ref $userinfo->{$user}) {
110                     IkiWiki::userinfo_setall($user, {
111                         'email' => '',
112                         'regdate' => time,
113                     });
114             }
115         }
116     
117         return $ret;
118     }
119     
120     sub formbuilder_setup (@) {
121         my %params=@_;
122     
123         my $form=$params{form};
124         my $session=$params{session};
125         my $cgi=$params{cgi};
126     
127         # if not under SSL, die before even showing a login form,
128         # unless the admin explicitly says it's fine
129         if (! exists $config{unixauth_requiressl}) {
130                 $config{unixauth_requiressl} = 1;
131         }
132         if ($config{unixauth_requiressl}) {
133             if ((! $config{sslcookie}) || (! exists $ENV{'HTTPS'})) {
134                 die("SSL required to login. Contact your administrator.<br>");
135             }
136         }
137     
138         if ($form->title eq "signin") {
139                 $form->field(name => "name", required => 0);
140                 $form->field(name => "password", type => "password", required => 0);
141                 
142                 if ($form->submitted) {
143                         my $submittype=$form->submitted;
144                         # Set required fields based on how form was submitted.
145                         my %required=(
146                                 "Login" => [qw(name password)],
147                         );
148                         foreach my $opt (@{$required{$submittype}}) {
149                                 $form->field(name => $opt, required => 1);
150                         }
151         
152                         # Validate password against name for Login.
153                         if ($submittype eq "Login") {
154                                 $form->field(
155                                         name => "password",
156                                         validate => sub {
157                                                 checkpassword($form->field("name"), shift);
158                                         },
159                                 );
160                         }
161                         
162                         # XXX is this reachable? looks like no
163                         elsif ($submittype eq "Login") {
164                                 $form->field( 
165                                         name => "name",
166                                         validate => sub {
167                                                 my $name=shift;
168                                                 length $name &&
169                                                 IkiWiki::userinfo_get($name, "regdate");
170                                         },
171                                 );
172                         }
173                 }
174                 else {
175                         # First time settings.
176                         $form->field(name => "name");
177                         if ($session->param("name")) {
178                                 $form->field(name => "name", value => $session->param("name"));
179                         }
180                 }
181         }
182         elsif ($form->title eq "preferences") {
183                 $form->field(name => "name", disabled => 1, 
184                         value => $session->param("name"), force => 1,
185                         fieldset => "login");
186                 $form->field(name => "password", disabled => 1, type => "password",
187                         fieldset => "login"),
188         }
189     }
190     
191     sub formbuilder (@) {
192         my %params=@_;
193     
194         my $form=$params{form};
195         my $session=$params{session};
196         my $cgi=$params{cgi};
197         my $buttons=$params{buttons};
198     
199         if ($form->title eq "signin") {
200                 if ($form->submitted && $form->validate) {
201                         if ($form->submitted eq 'Login') {
202                                 $session->param("name", $form->field("name"));
203                                 IkiWiki::cgi_postsignin($cgi, $session);
204                         }
205                 }
206         }
207         elsif ($form->title eq "preferences") {
208                 if ($form->submitted eq "Save Preferences" && $form->validate) {
209                         my $user_name=$form->field('name');
210                 }
211         }
212     }
213     
214     sub sessioncgi ($$) {
215         my $q=shift;
216         my $session=shift;
217     }
218     
219     1
221 """]]