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