Fix for variable scoping problem
[koha.git] / C4 / Auth.pm
blobe189c3419dd2919ee8fc1bdb6271e978b9b34202
1 # -*- tab-width: 8 -*-
2 # NOTE: This file uses 8-character tabs; do not change the tab size!
4 package C4::Auth;
6 # Copyright 2000-2002 Katipo Communications
8 # This file is part of Koha.
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.
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.
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
23 use strict;
24 use Digest::MD5 qw(md5_base64);
25 use CGI::Session;
27 require Exporter;
28 use C4::Context;
29 use C4::Output; # to get the template
30 use C4::Members;
31 use C4::Koha;
32 use C4::Branch; # GetBranches
34 # use utf8;
35 # use Net::LDAP;
36 # use Net::LDAP qw(:all);
38 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
40 # set the version for version checking
41 $VERSION = 3.00;
43 =head1 NAME
45 C4::Auth - Authenticates Koha users
47 =head1 SYNOPSIS
49 use CGI;
50 use C4::Auth;
52 my $query = new CGI;
54 my ($template, $borrowernumber, $cookie)
55 = get_template_and_user(
57 template_name => "opac-main.tmpl",
58 query => $query,
59 type => "opac",
60 authnotrequired => 1,
61 flagsrequired => {borrow => 1},
65 print $query->header(
66 -type => 'utf-8',
67 -cookie => $cookie
68 ), $template->output;
71 =head1 DESCRIPTION
73 The main function of this module is to provide
74 authentification. However the get_template_and_user function has
75 been provided so that a users login information is passed along
76 automatically. This gets loaded into the template.
78 =head1 FUNCTIONS
80 =over 2
82 =cut
84 @ISA = qw(Exporter);
85 @EXPORT = qw(
86 &checkauth
87 &get_template_and_user
90 =item get_template_and_user
92 my ($template, $borrowernumber, $cookie)
93 = get_template_and_user(
95 template_name => "opac-main.tmpl",
96 query => $query,
97 type => "opac",
98 authnotrequired => 1,
99 flagsrequired => {borrow => 1},
103 This call passes the C<query>, C<flagsrequired> and C<authnotrequired>
104 to C<&checkauth> (in this module) to perform authentification.
105 See C<&checkauth> for an explanation of these parameters.
107 The C<template_name> is then used to find the correct template for
108 the page. The authenticated users details are loaded onto the
109 template in the HTML::Template LOOP variable C<USER_INFO>. Also the
110 C<sessionID> is passed to the template. This can be used in templates
111 if cookies are disabled. It needs to be put as and input to every
112 authenticated page.
114 More information on the C<gettemplate> sub can be found in the
115 Output.pm module.
117 =cut
119 sub get_template_and_user {
120 my $in = shift;
121 my $template =
122 gettemplate( $in->{'template_name'}, $in->{'type'}, $in->{'query'} );
123 my ( $user, $cookie, $sessionID, $flags ) = checkauth(
124 $in->{'query'},
125 $in->{'authnotrequired'},
126 $in->{'flagsrequired'},
127 $in->{'type'}
128 ) unless ($in->{'template_name'}=~/maintenance/);
130 my $borrowernumber;
131 my $insecure = C4::Context->preference('insecure');
132 if ($user or $insecure) {
134 # load the template variables for stylesheets and JavaScript
135 $template->param( css_libs => $in->{'css_libs'} );
136 $template->param( css_module => $in->{'css_module'} );
137 $template->param( css_page => $in->{'css_page'} );
138 $template->param( css_widgets => $in->{'css_widgets'} );
140 $template->param( js_libs => $in->{'js_libs'} );
141 $template->param( js_module => $in->{'js_module'} );
142 $template->param( js_page => $in->{'js_page'} );
143 $template->param( js_widgets => $in->{'js_widgets'} );
145 # user info
146 $template->param( loggedinusername => $user );
147 $template->param( sessionID => $sessionID );
149 $borrowernumber = getborrowernumber($user);
150 my ( $borr, $alternativeflags ) =
151 GetMemberDetails( $borrowernumber );
152 my @bordat;
153 $bordat[0] = $borr;
154 $template->param( "USER_INFO" => \@bordat );
156 # We are going to use the $flags returned by checkauth
157 # to create the template's parameters that will indicate
158 # which menus the user can access.
159 if (( $flags && $flags->{superlibrarian}==1) or $insecure==1) {
160 $template->param( CAN_user_circulate => 1 );
161 $template->param( CAN_user_catalogue => 1 );
162 $template->param( CAN_user_parameters => 1 );
163 $template->param( CAN_user_borrowers => 1 );
164 $template->param( CAN_user_permission => 1 );
165 $template->param( CAN_user_reserveforothers => 1 );
166 $template->param( CAN_user_borrow => 1 );
167 $template->param( CAN_user_editcatalogue => 1 );
168 $template->param( CAN_user_updatecharge => 1 );
169 $template->param( CAN_user_acquisition => 1 );
170 $template->param( CAN_user_management => 1 );
171 $template->param( CAN_user_tools => 1 );
172 $template->param( CAN_user_editauthorities => 1 );
173 $template->param( CAN_user_serials => 1 );
174 $template->param( CAN_user_reports => 1 );
177 if ( $flags && $flags->{circulate} == 1 ) {
178 $template->param( CAN_user_circulate => 1 );
181 if ( $flags && $flags->{catalogue} == 1 ) {
182 $template->param( CAN_user_catalogue => 1 );
185 if ( $flags && $flags->{parameters} == 1 ) {
186 $template->param( CAN_user_parameters => 1 );
187 $template->param( CAN_user_management => 1 );
190 if ( $flags && $flags->{borrowers} == 1 ) {
191 $template->param( CAN_user_borrowers => 1 );
194 if ( $flags && $flags->{permissions} == 1 ) {
195 $template->param( CAN_user_permission => 1 );
198 if ( $flags && $flags->{reserveforothers} == 1 ) {
199 $template->param( CAN_user_reserveforothers => 1 );
202 if ( $flags && $flags->{borrow} == 1 ) {
203 $template->param( CAN_user_borrow => 1 );
206 if ( $flags && $flags->{editcatalogue} == 1 ) {
207 $template->param( CAN_user_editcatalogue => 1 );
210 if ( $flags && $flags->{updatecharges} == 1 ) {
211 $template->param( CAN_user_updatecharge => 1 );
214 if ( $flags && $flags->{acquisition} == 1 ) {
215 $template->param( CAN_user_acquisition => 1 );
218 if ( $flags && $flags->{tools} == 1 ) {
219 $template->param( CAN_user_tools => 1 );
222 if ( $flags && $flags->{editauthorities} == 1 ) {
223 $template->param( CAN_user_editauthorities => 1 );
226 if ( $flags && $flags->{serials} == 1 ) {
227 $template->param( CAN_user_serials => 1 );
230 if ( $flags && $flags->{reports} == 1 ) {
231 $template->param( CAN_user_reports => 1 );
234 if ( $in->{'type'} eq "intranet" ) {
235 $template->param(
236 intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
237 intranetstylesheet => C4::Context->preference("intranetstylesheet"),
238 IntranetNav => C4::Context->preference("IntranetNav"),
239 intranetuserjs => C4::Context->preference("intranetuserjs"),
240 TemplateEncoding => C4::Context->preference("TemplateEncoding"),
241 AmazonContent => C4::Context->preference("AmazonContent"),
242 LibraryName => C4::Context->preference("LibraryName"),
243 LoginBranchcode => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
244 LoginBranchname => (C4::Context->userenv?C4::Context->userenv->{"branchname"}:"insecure"),
245 LoginFirstname => (C4::Context->userenv?C4::Context->userenv->{"firstname"}:"Bel"),
246 LoginSurname => C4::Context->userenv?C4::Context->userenv->{"surname"}:"Inconnu",
247 AutoLocation => C4::Context->preference("AutoLocation"),
248 hide_marc => C4::Context->preference("hide_marc"),
249 patronimages => C4::Context->preference("patronimages"),
250 "BiblioDefaultView".C4::Context->preference("IntranetBiblioDefaultView") => 1,
251 advancedMARCEditor => C4::Context->preference("advancedMARCEditor"),
252 suggestion => C4::Context->preference("suggestion"),
253 virtualshelves => C4::Context->preference("virtualshelves"),
254 LibraryName => C4::Context->preference("LibraryName"),
255 KohaAdminEmailAddress => "" . C4::Context->preference("KohaAdminEmailAddress"),
256 IntranetmainUserblock => C4::Context->preference("IntranetmainUserblock"),
257 IndependantBranches => C4::Context->preference("IndependantBranches"),
258 CircAutocompl => C4::Context->preference("CircAutocompl"),
259 yuipath => C4::Context->preference("yuipath"),
262 else {
263 warn "template type should be OPAC, here it is=[" . $in->{'type'} . "]" unless ( $in->{'type'} eq 'opac' );
264 my $LibraryNameTitle = C4::Context->preference("LibraryName");
265 $LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi;
266 $LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg;
267 $template->param(
268 KohaAdminEmailAddress => "" . C4::Context->preference("KohaAdminEmailAddress"),
269 suggestion => "" . C4::Context->preference("suggestion"),
270 virtualshelves => "" . C4::Context->preference("virtualshelves"),
271 OpacNav => "" . C4::Context->preference("OpacNav"),
272 opacheader => "" . C4::Context->preference("opacheader"),
273 opaccredits => "" . C4::Context->preference("opaccredits"),
274 opacsmallimage => "" . C4::Context->preference("opacsmallimage"),
275 opaclargeimage => "" . C4::Context->preference("opaclargeimage"),
276 opaclayoutstylesheet => "". C4::Context->preference("opaclayoutstylesheet"),
277 opaccolorstylesheet => "". C4::Context->preference("opaccolorstylesheet"),
278 opaclanguagesdisplay => "". C4::Context->preference("opaclanguagesdisplay"),
279 opacuserlogin => "" . C4::Context->preference("opacuserlogin"),
280 opacbookbag => "" . C4::Context->preference("opacbookbag"),
281 TemplateEncoding => "". C4::Context->preference("TemplateEncoding"),
282 AmazonContent => "" . C4::Context->preference("AmazonContent"),
283 LibraryName => "" . C4::Context->preference("LibraryName"),
284 LibraryNameTitle => "" . $LibraryNameTitle,
285 LoginBranchcode => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
286 LoginBranchname => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"",
287 LoginFirstname => (C4::Context->userenv?C4::Context->userenv->{"firstname"}:"Bel"),
288 LoginSurname => C4::Context->userenv?C4::Context->userenv->{"surname"}:"Inconnu",
289 OpacPasswordChange => C4::Context->preference("OpacPasswordChange"),
290 opacreadinghistory => C4::Context->preference("opacreadinghistory"),
291 opacuserjs => C4::Context->preference("opacuserjs"),
292 OpacCloud => C4::Context->preference("OpacCloud"),
293 OpacTopissue => C4::Context->preference("OpacTopissue"),
294 OpacAuthorities => C4::Context->preference("OpacAuthorities"),
295 OpacBrowser => C4::Context->preference("OpacBrowser"),
296 RequestOnOpac => C4::Context->preference("RequestOnOpac"),
297 reviewson => C4::Context->preference("reviewson"),
298 hide_marc => C4::Context->preference("hide_marc"),
299 patronimages => C4::Context->preference("patronimages"),
300 mylibraryfirst => C4::Context->preference("SearchMyLibraryFirst"),
301 "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
304 return ( $template, $borrowernumber, $cookie );
307 =item checkauth
309 ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
311 Verifies that the user is authorized to run this script. If
312 the user is authorized, a (userid, cookie, session-id, flags)
313 quadruple is returned. If the user is not authorized but does
314 not have the required privilege (see $flagsrequired below), it
315 displays an error page and exits. Otherwise, it displays the
316 login page and exits.
318 Note that C<&checkauth> will return if and only if the user
319 is authorized, so it should be called early on, before any
320 unfinished operations (e.g., if you've opened a file, then
321 C<&checkauth> won't close it for you).
323 C<$query> is the CGI object for the script calling C<&checkauth>.
325 The C<$noauth> argument is optional. If it is set, then no
326 authorization is required for the script.
328 C<&checkauth> fetches user and session information from C<$query> and
329 ensures that the user is authorized to run scripts that require
330 authorization.
332 The C<$flagsrequired> argument specifies the required privileges
333 the user must have if the username and password are correct.
334 It should be specified as a reference-to-hash; keys in the hash
335 should be the "flags" for the user, as specified in the Members
336 intranet module. Any key specified must correspond to a "flag"
337 in the userflags table. E.g., { circulate => 1 } would specify
338 that the user must have the "circulate" privilege in order to
339 proceed. To make sure that access control is correct, the
340 C<$flagsrequired> parameter must be specified correctly.
342 The C<$type> argument specifies whether the template should be
343 retrieved from the opac or intranet directory tree. "opac" is
344 assumed if it is not specified; however, if C<$type> is specified,
345 "intranet" is assumed if it is not "opac".
347 If C<$query> does not have a valid session ID associated with it
348 (i.e., the user has not logged in) or if the session has expired,
349 C<&checkauth> presents the user with a login page (from the point of
350 view of the original script, C<&checkauth> does not return). Once the
351 user has authenticated, C<&checkauth> restarts the original script
352 (this time, C<&checkauth> returns).
354 The login page is provided using a HTML::Template, which is set in the
355 systempreferences table or at the top of this file. The variable C<$type>
356 selects which template to use, either the opac or the intranet
357 authentification template.
359 C<&checkauth> returns a user ID, a cookie, and a session ID. The
360 cookie should be sent back to the browser; it verifies that the user
361 has authenticated.
363 =cut
365 sub checkauth {
366 my $query = shift;
367 # warn "Checking Auth";
368 # $authnotrequired will be set for scripts which will run without authentication
369 my $authnotrequired = shift;
370 my $flagsrequired = shift;
371 my $type = shift;
372 $type = 'opac' unless $type;
374 my $dbh = C4::Context->dbh;
375 my $timeout = C4::Context->preference('timeout');
376 $timeout = 600 unless $timeout;
379 # If Version syspref is unavailable, it means Koha is beeing installed,
380 # and so we must redirect to OPAC maintenance page or to the WebInstaller
381 #warn "about to check version";
382 unless (C4::Context->preference('Version')) {
383 if ($type ne 'opac') {
384 warn "Install required, redirecting to Installer";
385 print $query->redirect("/cgi-bin/koha/installer/install.pl");
387 else {
388 warn "OPAC Install required, redirecting to maintenance";
389 print $query->redirect("/cgi-bin/koha/maintenance.pl");
391 exit;
395 # state variables
396 my $loggedin = 0;
397 my %info;
398 my ( $userid, $cookie, $sessionID, $flags );
399 my $logout = $query->param('logout.x');
400 if ( $userid = $ENV{'REMOTE_USER'} ) {
401 # Using Basic Authentication, no cookies required
402 $cookie = $query->cookie(
403 -name => 'CGISESSID',
404 -value => '',
405 -expires => ''
407 $loggedin = 1;
409 elsif ( $sessionID = $query->cookie("CGISESSID")) {
410 my $storage_method = C4::Context->preference('SessionStorage');
411 my $session;
412 if ($storage_method eq 'mysql'){
413 $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
415 else {
416 # catch all defaults to tmp should work on all systems
417 $session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
419 C4::Context->_new_userenv($sessionID);
420 if ($session){
421 C4::Context::set_userenv(
422 $session->param('number'), $session->param('id'),
423 $session->param('cardnumber'), $session->param('firstname'),
424 $session->param('surname'), $session->param('branch'),
425 $session->param('branchname'), $session->param('flags'),
426 $session->param('emailaddress'), $session->param('branchprinter')
428 # warn "".$session->param('cardnumber').", ".$session->param('firstname').",
429 # ".$session->param('surname').", ".$session->param('branch');
431 my $ip;
432 my $lasttime;
433 if ($session) {
434 $ip = $session->param('ip');
435 $lasttime = $session->param('lasttime');
436 $userid = $session->param('id');
440 if ($logout) {
442 # voluntary logout the user
444 $session->flush;
445 $session->delete();
446 C4::Context->_unset_userenv($sessionID);
447 $sessionID = undef;
448 $userid = undef;
449 open L, ">>/tmp/sessionlog";
450 my $time = localtime( time() );
451 printf L "%20s from %16s logged out at %30s (manually).\n", $userid,
452 $ip, $time;
453 close L;
455 if ($userid) {
456 if ( $lasttime < time() - $timeout ) {
457 # timed logout
458 $info{'timed_out'} = 1;
459 $session->delete();
460 C4::Context->_unset_userenv($sessionID);
461 $userid = undef;
462 $sessionID = undef;
463 open L, ">>/tmp/sessionlog";
464 my $time = localtime( time() );
465 printf L "%20s from %16s logged out at %30s (inactivity).\n",
466 $userid, $ip, $time;
467 close L;
469 elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
470 # Different ip than originally logged in from
471 $info{'oldip'} = $ip;
472 $info{'newip'} = $ENV{'REMOTE_ADDR'};
473 $info{'different_ip'} = 1;
474 $session->delete();
475 C4::Context->_unset_userenv($sessionID);
476 $sessionID = undef;
477 $userid = undef;
478 open L, ">>/tmp/sessionlog";
479 my $time = localtime( time() );
480 printf L
481 "%20s from logged out at %30s (ip changed from %16s to %16s).\n",
482 $userid, $time, $ip, $info{'newip'};
483 close L;
485 else {
486 $cookie = $query->cookie( CGISESSID => $session->id );
487 $session->param('lasttime',time());
488 $flags = haspermission( $dbh, $userid, $flagsrequired );
489 if ($flags) {
490 $loggedin = 1;
492 else {
493 $info{'nopermission'} = 1;
498 unless ($userid) {
499 my $storage_method = C4::Context->preference('SessionStorage');
500 my $session;
501 if ($storage_method eq 'mysql'){
502 $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
504 else {
505 # catch all defaults to tmp should work on all systems
506 $session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
509 my $sessionID;
510 if ($session) {
511 $sessionID = $session->id;
513 $userid = $query->param('userid');
514 C4::Context->_new_userenv($sessionID);
515 my $password = $query->param('password');
516 C4::Context->_new_userenv($sessionID);
517 my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
518 if ($return) {
519 open L, ">>/tmp/sessionlog";
520 my $time = localtime( time() );
521 printf L "%20s from %16s logged in at %30s.\n", $userid,
522 $ENV{'REMOTE_ADDR'}, $time;
523 close L;
524 $cookie = $query->cookie(CGISESSID => $sessionID);
525 if ( $flags = haspermission( $dbh, $userid, $flagsrequired ) ) {
526 $loggedin = 1;
528 else {
529 $info{'nopermission'} = 1;
530 C4::Context->_unset_userenv($sessionID);
532 if ( $return == 1 ) {
533 my (
534 $borrowernumber, $firstname, $surname,
535 $userflags, $branchcode, $branchname,
536 $branchprinter, $emailaddress
538 my $sth =
539 $dbh->prepare(
540 "select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname,branches.branchprinter as branchprinter, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where userid=?"
542 $sth->execute($userid);
544 $borrowernumber, $firstname, $surname,
545 $userflags, $branchcode, $branchname,
546 $branchprinter, $emailaddress
548 = $sth->fetchrow
549 if ( $sth->rows );
551 # warn "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
552 unless ( $sth->rows ) {
553 my $sth =
554 $dbh->prepare(
555 "select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname, branches.branchprinter as branchprinter, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where cardnumber=?"
557 $sth->execute($cardnumber);
559 $borrowernumber, $firstname, $surname,
560 $userflags, $branchcode, $branchname,
561 $branchprinter, $emailaddress
563 = $sth->fetchrow
564 if ( $sth->rows );
566 # warn "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
567 unless ( $sth->rows ) {
568 $sth->execute($userid);
570 $borrowernumber, $firstname, $surname, $userflags,
571 $branchcode, $branchname, $branchprinter, $emailaddress
573 = $sth->fetchrow
574 if ( $sth->rows );
578 # launch a sequence to check if we have a ip for the branch, if we have one we replace the branchcode of the userenv by the branch bound in the ip.
579 my $ip = $ENV{'REMOTE_ADDR'};
580 # if they specify at login, use that
581 if ($query->param('branch')) {
582 $branchcode = $query->param('branch');
583 $branchname = GetBranchName($branchcode);
585 my $branches = GetBranches();
586 my @branchesloop;
587 foreach my $br ( keys %$branches ) {
588 # now we work with the treatment of ip
589 my $domain = $branches->{$br}->{'branchip'};
590 if ( $domain && $ip =~ /^$domain/ ) {
591 $branchcode = $branches->{$br}->{'branchcode'};
593 # new op dev : add the branchprinter and branchname in the cookie
594 $branchprinter = $branches->{$br}->{'branchprinter'};
595 $branchname = $branches->{$br}->{'branchname'};
598 $session->param('number',$borrowernumber);
599 $session->param('id',$userid);
600 $session->param('cardnumber',$cardnumber);
601 $session->param('firstname',$firstname);
602 $session->param('surname',$surname);
603 $session->param('branch',$branchcode);
604 $session->param('branchname',$branchname);
605 $session->param('flags',$userflags);
606 $session->param('emailaddress',$emailaddress);
607 $session->param('ip',$session->remote_addr());
608 $session->param('lasttime',time());
609 # warn "".$session->param('cardnumber').", ".$session->param('firstname').",
610 # ".$session->param('surname').", ".$session->param('branch');
612 elsif ( $return == 2 ) {
613 #We suppose the user is the superlibrarian
614 $session->param('number',0);
615 $session->param('id',C4::Context->config('user'));
616 $session->param('cardnumber',C4::Context->config('user'));
617 $session->param('firstname',C4::Context->config('user'));
618 $session->param('surname',C4::Context->config('user'));
619 $session->param('branch','NO_LIBRARY_SET');
620 $session->param('branchname','NO_LIBRARY_SET');
621 $session->param('flags',1);
622 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
623 $session->param('ip',$session->remote_addr());
624 $session->param('lasttime',time());
626 if ($session){
627 C4::Context::set_userenv(
628 $session->param('number'), $session->param('id'),
629 $session->param('cardnumber'), $session->param('firstname'),
630 $session->param('surname'), $session->param('branch'),
631 $session->param('branchname'), $session->param('flags'),
632 $session->param('emailaddress'), $session->param('branchprinter')
637 else {
638 if ($userid) {
639 $info{'invalid_username_or_password'} = 1;
640 C4::Context->_unset_userenv($sessionID);
644 my $insecure = C4::Context->boolean_preference('insecure');
646 # finished authentification, now respond
647 if ( $loggedin || $authnotrequired || ( defined($insecure) && $insecure ) )
649 # successful login
650 unless ($cookie) {
651 $cookie = $query->cookie( CGISESSID => ''
654 return ( $userid, $cookie, $sessionID, $flags );
660 # AUTH rejected, show the login/password template, after checking the DB.
664 # get the inputs from the incoming query
665 my @inputs = ();
666 foreach my $name ( param $query) {
667 (next) if ( $name eq 'userid' || $name eq 'password' );
668 my $value = $query->param($name);
669 push @inputs, { name => $name, value => $value };
671 # get the branchloop, which we need for authentication
672 my $branches = GetBranches();
673 my @branch_loop;
674 for my $branch_hash (keys %$branches) {
675 push @branch_loop, {branchcode => "$branch_hash", branchname => $branches->{$branch_hash}->{'branchname'}, };
678 # check that database and koha version are the same
679 # there is no DB version, it's a fresh install,
680 # go to web installer
681 # there is a DB version, compare it to the code version
682 my $kohaversion=C4::Context::KOHAVERSION;
683 # remove the 3 last . to have a Perl number
684 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
685 # warn "kohaversion : $kohaversion";
686 if (C4::Context->preference('Version') < $kohaversion){
687 if ($type ne 'opac'){
688 warn "Database update needed, redirecting to Installer. Database is ".C4::Context->preference('Version')." and Koha is : ".C4::Context->config("kohaversion");
689 print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
690 } else {
691 warn "OPAC :Database update needed, redirecting to maintenance. Database is ".C4::Context->preference('Version')." and Koha is : ".C4::Context->config("kohaversion");
692 print $query->redirect("/cgi-bin/koha/maintenance.pl");
694 exit;
696 my $template_name;
697 if ( $type eq 'opac' ) {
698 $template_name = "opac-auth.tmpl";
700 else {
701 $template_name = "auth.tmpl";
703 my $template = gettemplate( $template_name, $type, $query );
704 $template->param(branchloop => \@branch_loop,);
705 $template->param(
706 login => 1,
707 INPUTS => \@inputs,
708 suggestion => C4::Context->preference("suggestion"),
709 virtualshelves => C4::Context->preference("virtualshelves"),
710 opaclargeimage => C4::Context->preference("opaclargeimage"),
711 LibraryName => C4::Context->preference("LibraryName"),
712 OpacNav => C4::Context->preference("OpacNav"),
713 opaccredits => C4::Context->preference("opaccredits"),
714 opacreadinghistory => C4::Context->preference("opacreadinghistory"),
715 opacsmallimage => C4::Context->preference("opacsmallimage"),
716 opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
717 opaccolorstylesheet => C4::Context->preference("opaccolorstylesheet"),
718 opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
719 opacuserjs => C4::Context->preference("opacuserjs"),
721 intranetcolorstylesheet =>
722 C4::Context->preference("intranetcolorstylesheet"),
723 intranetstylesheet => C4::Context->preference("intranetstylesheet"),
724 IntranetNav => C4::Context->preference("IntranetNav"),
725 intranetuserjs => C4::Context->preference("intranetuserjs"),
726 TemplateEncoding => C4::Context->preference("TemplateEncoding"),
727 IndependantBranches => C4::Context->preference("IndependantBranches"),
729 $template->param( loginprompt => 1 ) unless $info{'nopermission'};
731 my $self_url = $query->url( -absolute => 1 );
732 $template->param(
733 url => $self_url,
734 LibraryName => => C4::Context->preference("LibraryName"),
736 $template->param( \%info );
737 # $cookie = $query->cookie(CGISESSID => $session->id
738 # );
739 print $query->header(
740 -type => 'text/html',
741 -charset => 'utf-8',
742 -cookie => $cookie
744 $template->output;
745 exit;
748 sub checkpw {
750 my ( $dbh, $userid, $password ) = @_;
752 # INTERNAL AUTH
753 my $sth =
754 $dbh->prepare(
755 "select password,cardnumber,borrowernumber,userid,firstname,surname,branchcode,flags from borrowers where userid=?"
757 $sth->execute($userid);
758 if ( $sth->rows ) {
759 my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
760 $surname, $branchcode, $flags )
761 = $sth->fetchrow;
762 if ( md5_base64($password) eq $md5password ) {
764 C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
765 $firstname, $surname, $branchcode, $flags );
766 return 1, $cardnumber;
769 $sth =
770 $dbh->prepare(
771 "select password,cardnumber,borrowernumber,userid, firstname,surname,branchcode,flags from borrowers where cardnumber=?"
773 $sth->execute($userid);
774 if ( $sth->rows ) {
775 my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
776 $surname, $branchcode, $flags )
777 = $sth->fetchrow;
778 if ( md5_base64($password) eq $md5password ) {
780 C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
781 $firstname, $surname, $branchcode, $flags );
782 return 1, $userid;
785 if ( $userid && $userid eq C4::Context->config('user')
786 && "$password" eq C4::Context->config('pass') )
789 # Koha superuser account
790 # C4::Context->set_userenv(0,0,C4::Context->config('user'),C4::Context->config('user'),C4::Context->config('user'),"",1);
791 return 2;
793 if ( $userid && $userid eq 'demo'
794 && "$password" eq 'demo'
795 && C4::Context->config('demo') )
798 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
799 # some features won't be effective : modify systempref, modify MARC structure,
800 return 2;
802 return 0;
805 sub getuserflags {
806 my $cardnumber = shift;
807 my $dbh = shift;
808 my $userflags;
809 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE cardnumber=?");
810 $sth->execute($cardnumber);
811 my ($flags) = $sth->fetchrow;
812 $flags = 0 unless $flags;
813 $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
814 $sth->execute;
816 while ( my ( $bit, $flag, $defaulton ) = $sth->fetchrow ) {
817 if ( ( $flags & ( 2**$bit ) ) || $defaulton ) {
818 $userflags->{$flag} = 1;
820 else {
821 $userflags->{$flag} = 0;
824 return $userflags;
827 sub haspermission {
828 my ( $dbh, $userid, $flagsrequired ) = @_;
829 my $sth = $dbh->prepare("SELECT cardnumber FROM borrowers WHERE userid=?");
830 $sth->execute($userid);
831 my ($cardnumber) = $sth->fetchrow;
832 ($cardnumber) || ( $cardnumber = $userid );
833 my $flags = getuserflags( $cardnumber, $dbh );
834 my $configfile;
835 if ( $userid eq C4::Context->config('user') ) {
837 # Super User Account from /etc/koha.conf
838 $flags->{'superlibrarian'} = 1;
840 if ( $userid eq 'demo' && C4::Context->config('demo') ) {
842 # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
843 $flags->{'superlibrarian'} = 1;
845 return $flags if $flags->{superlibrarian};
846 foreach ( keys %$flagsrequired ) {
847 return $flags if $flags->{$_};
849 return 0;
852 sub getborrowernumber {
853 my ($userid) = @_;
854 my $dbh = C4::Context->dbh;
855 for my $field ( 'userid', 'cardnumber' ) {
856 my $sth =
857 $dbh->prepare("select borrowernumber from borrowers where $field=?");
858 $sth->execute($userid);
859 if ( $sth->rows ) {
860 my ($bnumber) = $sth->fetchrow;
861 return $bnumber;
864 return 0;
867 END { } # module clean-up code here (global destructor)
869 __END__
871 =back
873 =head1 SEE ALSO
875 CGI(3)
877 C4::Output(3)
879 Digest::MD5(3)
881 =cut