Adding labels generator.
[koha.git] / installer / InstallAuth.pm
1 # -*- tab-width: 8 -*-
2 # NOTE: This file uses 8-character tabs; do not change the tab size!
3
4 package InstallAuth;
5
6 # Copyright 2000-2002 Katipo Communications
7 #
8 # This file is part of Koha.
9 #
10 # Koha is free software; you can redistribute it and/or modify it under the
11 # terms of the GNU General Public License as published by the Free Software
12 # Foundation; either version 2 of the License, or (at your option) any later
13 # version.
14 #
15 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
16 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License along with
20 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
21 # Suite 330, Boston, MA  02111-1307 USA
22
23 use strict;
24 use Digest::MD5 qw(md5_base64);
25
26 require Exporter;
27 use C4::Context;
28 use C4::Output;
29 use C4::Koha;
30 use CGI::Session;
31
32 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
33
34 # set the version for version checking
35 $VERSION = do { my @v = '$Revision$' =~ /\d+/g;
36     shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v );
37 };
38
39 =head1 NAME
40
41 InstallAuth - Authenticates Koha users for Install process
42
43 =head1 SYNOPSIS
44
45   use CGI;
46   use InstallAuth;
47
48   my $query = new CGI;
49
50   my ($template, $borrowernumber, $cookie) 
51     = get_template_and_user({template_name   => "opac-main.tmpl",
52                              query           => $query,
53                              type            => "opac",
54                              authnotrequired => 1,
55                              flagsrequired   => {borrow => 1},
56                           });
57
58   print $query->header(
59     -type => 'utf-8',
60     -cookie => $cookie
61   ), $template->output;
62
63
64 =head1 DESCRIPTION
65
66     The main function of this module is to provide
67     authentification. However the get_template_and_user function has
68     been provided so that a users login information is passed along
69     automatically. This gets loaded into the template.
70     This package is different from C4::Auth in so far as 
71     C4::Auth uses many preferences which are supposed NOT to be obtainable when installing the database.
72     
73     As in C4::Auth, Authentication is based on cookies.
74
75 =head1 FUNCTIONS
76
77 =over 2
78
79 =cut
80
81 @ISA    = qw(Exporter);
82 @EXPORT = qw(
83   &checkauth
84   &get_template_and_user
85   &setlanguagecookie
86 );
87
88 =item get_template_and_user
89
90   my ($template, $borrowernumber, $cookie)
91     = get_template_and_user({template_name   => "opac-main.tmpl",
92                              query           => $query,
93                              type            => "opac",
94                              authnotrequired => 1,
95                              flagsrequired   => {borrow => 1},
96                           });
97
98     This call passes the C<query>, C<flagsrequired> and C<authnotrequired>
99     to C<&checkauth> (in this module) to perform authentification.
100     See C<&checkauth> for an explanation of these parameters.
101
102     The C<template_name> is then used to find the correct template for
103     the page. The authenticated users details are loaded onto the
104     template in the HTML::Template LOOP variable C<USER_INFO>. Also the
105     C<sessionID> is passed to the template. This can be used in templates
106     if cookies are disabled. It needs to be put as and input to every
107     authenticated page.
108
109     More information on the C<gettemplate> sub can be found in the
110     Output.pm module.
111
112 =cut
113
114 sub get_template_and_user {
115     my $in       = shift;
116     my $query    = $in->{'query'};
117     my $language = $query->cookie('KohaOpacLanguage');
118     my $path =
119       C4::Context->config('intrahtdocs') . "/prog/"
120       . ( $language ? $language : "en" );
121     my $template = HTML::Template::Pro->new(
122         filename          => "$path/" . $in->{template_name},
123         die_on_bad_params => 1,
124         global_vars       => 1,
125         case_sensitive    => 1,
126         path              => ["$path/includes"]
127     );
128
129     my ( $user, $cookie, $sessionID, $flags ) = checkauth(
130         $in->{'query'},
131         $in->{'authnotrequired'},
132         $in->{'flagsrequired'},
133         $in->{'type'}
134     );
135
136     #     use Data::Dumper;warn "utilisateur $user cookie : ".Dumper($cookie);
137
138     my $borrowernumber;
139     if ($user) {
140         $template->param( loggedinusername => $user );
141         $template->param( sessionID        => $sessionID );
142
143         # We are going to use the $flags returned by checkauth
144         # to create the template's parameters that will indicate
145         # which menus the user can access.
146         if ( ( $flags && $flags->{superlibrarian} == 1 ) ) {
147             $template->param( CAN_user_circulate        => 1 );
148             $template->param( CAN_user_catalogue        => 1 );
149             $template->param( CAN_user_parameters       => 1 );
150             $template->param( CAN_user_borrowers        => 1 );
151             $template->param( CAN_user_permission       => 1 );
152             $template->param( CAN_user_reserveforothers => 1 );
153             $template->param( CAN_user_borrow           => 1 );
154             $template->param( CAN_user_editcatalogue    => 1 );
155             $template->param( CAN_user_updatecharge     => 1 );
156             $template->param( CAN_user_acquisition      => 1 );
157             $template->param( CAN_user_management       => 1 );
158             $template->param( CAN_user_tools            => 1 );
159             $template->param( CAN_user_editauthorities  => 1 );
160             $template->param( CAN_user_serials          => 1 );
161             $template->param( CAN_user_reports          => 1 );
162         }
163     }
164     return ( $template, $borrowernumber, $cookie );
165 }
166
167 =item checkauth
168
169   ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
170
171 Verifies that the user is authorized to run this script.  If
172 the user is authorized, a (userid, cookie, session-id, flags)
173 quadruple is returned.  If the user is not authorized but does
174 not have the required privilege (see $flagsrequired below), it
175 displays an error page and exits.  Otherwise, it displays the
176 login page and exits.
177
178 Note that C<&checkauth> will return if and only if the user
179 is authorized, so it should be called early on, before any
180 unfinished operations (e.g., if you've opened a file, then
181 C<&checkauth> won't close it for you).
182
183 C<$query> is the CGI object for the script calling C<&checkauth>.
184
185 The C<$noauth> argument is optional. If it is set, then no
186 authorization is required for the script.
187
188 C<&checkauth> fetches user and session information from C<$query> and
189 ensures that the user is authorized to run scripts that require
190 authorization.
191
192 The C<$flagsrequired> argument specifies the required privileges
193 the user must have if the username and password are correct.
194 It should be specified as a reference-to-hash; keys in the hash
195 should be the "flags" for the user, as specified in the Members
196 intranet module. Any key specified must correspond to a "flag"
197 in the userflags table. E.g., { circulate => 1 } would specify
198 that the user must have the "circulate" privilege in order to
199 proceed. To make sure that access control is correct, the
200 C<$flagsrequired> parameter must be specified correctly.
201
202 The C<$type> argument specifies whether the template should be
203 retrieved from the opac or intranet directory tree.  "opac" is
204 assumed if it is not specified; however, if C<$type> is specified,
205 "intranet" is assumed if it is not "opac".
206
207 If C<$query> does not have a valid session ID associated with it
208 (i.e., the user has not logged in) or if the session has expired,
209 C<&checkauth> presents the user with a login page (from the point of
210 view of the original script, C<&checkauth> does not return). Once the
211 user has authenticated, C<&checkauth> restarts the original script
212 (this time, C<&checkauth> returns).
213
214 The login page is provided using a HTML::Template, which is set in the
215 systempreferences table or at the top of this file. The variable C<$type>
216 selects which template to use, either the opac or the intranet 
217 authentification template.
218
219 C<&checkauth> returns a user ID, a cookie, and a session ID. The
220 cookie should be sent back to the browser; it verifies that the user
221 has authenticated.
222
223 =cut
224
225 sub checkauth {
226     my $query = shift;
227
228 # $authnotrequired will be set for scripts which will run without authentication
229     my $authnotrequired = shift;
230     my $flagsrequired   = shift;
231     my $type            = shift;
232     $type = 'intranet' unless $type;
233
234     my $dbh = C4::Context->dbh();
235     my $template_name;
236     $template_name = "installer/auth.tmpl";
237
238     # state variables
239     my $loggedin = 0;
240     my %info;
241     my ( $userid, $cookie, $sessionID, $flags, $envcookie );
242     my $logout = $query->param('logout.x');
243     if ( $sessionID = $query->cookie("CGISESSID") ) {
244         C4::Context->_new_userenv($sessionID);
245         my $session =
246           new CGI::Session( "driver:File", $sessionID,
247             { Directory => '/tmp' } );
248         if ( $session->param('cardnumber') ) {
249             C4::Context::set_userenv(
250                 $session->param('number'),
251                 $session->param('id'),
252                 $session->param('cardnumber'),
253                 $session->param('firstname'),
254                 $session->param('surname'),
255                 $session->param('branch'),
256                 $session->param('branchname'),
257                 $session->param('flags'),
258                 $session->param('emailaddress'),
259                 $session->param('branchprinter')
260             );
261             $cookie   = $query->cookie( CGISESSID => $session->id );
262             $loggedin = 1;
263             $userid   = $session->param('cardnumber');
264         }
265         my ( $ip, $lasttime );
266
267         if ($logout) {
268
269             # voluntary logout the user
270             C4::Context->_unset_userenv($sessionID);
271             $sessionID = undef;
272             $userid    = undef;
273             open L, ">>/tmp/sessionlog";
274             my $time = localtime( time() );
275             printf L "%20s from %16s logged out at %30s (manually).\n", $userid,
276               $ip, $time;
277             close L;
278         }
279     }
280     unless ($userid) {
281         my $session =
282           new CGI::Session( "driver:File", undef, { Directory => '/tmp' } );
283         $sessionID = $session->id;
284         $userid    = $query->param('userid');
285         C4::Context->_new_userenv($sessionID);
286         my $password = $query->param('password');
287         C4::Context->_new_userenv($sessionID);
288         my ( $return, $cardnumber ) = checkpw( $userid, $password );
289         if ($return) {
290             $loggedin = 1;
291             open L, ">>/tmp/sessionlog";
292             my $time = localtime( time() );
293             printf L "%20s from %16s logged in  at %30s.\n", $userid,
294               $ENV{'REMOTE_ADDR'}, $time;
295             close L;
296             $cookie = $query->cookie( CGISESSID => $sessionID );
297             if ( $return == 2 ) {
298
299            #Only superlibrarian should have access to this page.
300            #Since if it is a user, it is supposed that there is a borrower table
301            #And thus that data structure is loaded.
302                 my $hash = C4::Context::set_userenv(
303                     0,                           0,
304                     C4::Context->config('user'), C4::Context->config('user'),
305                     C4::Context->config('user'), "",
306                     "NO_LIBRARY_SET",            1,
307                     ""
308                 );
309                 $session->param( 'number',     0 );
310                 $session->param( 'id',         C4::Context->config('user') );
311                 $session->param( 'cardnumber', C4::Context->config('user') );
312                 $session->param( 'firstname',  C4::Context->config('user') );
313                 $session->param( 'surname',    C4::Context->config('user'), );
314                 $session->param( 'branch',     'NO_LIBRARY_SET' );
315                 $session->param( 'branchname', 'NO_LIBRARY_SET' );
316                 $session->param( 'flags',      1 );
317                 $session->param( 'emailaddress',
318                     C4::Context->preference('KohaAdminEmailAddress') );
319                 $session->param( 'ip',       $session->remote_addr() );
320                 $session->param( 'lasttime', time() );
321                 $userid = C4::Context->config('user');
322             }
323         }
324         else {
325             if ($userid) {
326                 $info{'invalid_username_or_password'} = 1;
327                 C4::Context->_unset_userenv($sessionID);
328             }
329         }
330     }
331
332     # finished authentification, now respond
333     if ($loggedin) {
334
335         # successful login
336         unless ($cookie) {
337             $cookie = $query->cookie(
338                 -name    => 'CGISESSID',
339                 -value   => '',
340                 -expires => ''
341             );
342         }
343         if ($envcookie) {
344             return ( $userid, [ $cookie, $envcookie ], $sessionID, $flags );
345         }
346         else {
347             return ( $userid, $cookie, $sessionID, $flags );
348         }
349     }
350
351     # else we have a problem...
352     # get the inputs from the incoming query
353     my @inputs = ();
354     foreach my $name ( param $query) {
355         (next) if ( $name eq 'userid' || $name eq 'password' );
356         my $value = $query->param($name);
357         push @inputs, { name => $name, value => $value };
358     }
359
360     my $path =
361       C4::Context->config('intrahtdocs') . "/prog/"
362       . ( $query->param('language') ? $query->param('language') : "en" );
363     my $template = HTML::Template::Pro->new(
364         filename          => "$path/$template_name",
365         die_on_bad_params => 1,
366         global_vars       => 1,
367         case_sensitive    => 1,
368         path              => ["$path/includes"]
369     );
370     $template->param(
371         INPUTS => \@inputs,
372
373     );
374     $template->param( login => 1 );
375     $template->param( loginprompt => 1 ) unless $info{'nopermission'};
376
377     my $self_url = $query->url( -absolute => 1 );
378     $template->param( url => $self_url, );
379     $template->param( \%info );
380     $cookie = $query->cookie(
381         -name    => 'CGISESSID',
382         -value   => $sessionID,
383         -expires => ''
384     );
385     print $query->header(
386         -type    => 'text/html; charset=utf-8',
387         -cookie  => $cookie
388       ),
389       $template->output;
390     exit;
391 }
392
393 sub checkpw {
394
395     my ( $userid, $password ) = @_;
396
397     if (   $userid
398         && $userid     eq C4::Context->config('user')
399         && "$password" eq C4::Context->config('pass') )
400     {
401
402         # Koha superuser account
403         C4::Context->set_userenv(
404             0, 0,
405             C4::Context->config('user'),
406             C4::Context->config('user'),
407             C4::Context->config('user'),
408             "", 1
409         );
410         return 2;
411     }
412     if (   $userid
413         && $userid     eq 'demo'
414         && "$password" eq 'demo'
415         && C4::Context->config('demo') )
416     {
417
418 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
419 # some features won't be effective : modify systempref, modify MARC structure,
420         return 2;
421     }
422     return 0;
423 }
424
425 END { }    # module clean-up code here (global destructor)
426 1;
427 __END__
428
429 =back
430
431 =head1 SEE ALSO
432
433 CGI(3)
434
435 C4::Output(3)
436
437 Digest::MD5(3)
438
439 =cut