3 # NOTE: This file uses 8-character tabs; do not change the tab size!
7 # Copyright 2000-2002 Katipo Communications
9 # This file is part of Koha.
11 # Koha is free software; you can redistribute it and/or modify it under the
12 # terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
16 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
17 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License along with
21 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
22 # Suite 330, Boston, MA 02111-1307 USA
25 use Digest::MD5 qw(md5_base64);
30 use C4::Output; # to get the template
33 use C4::Branch; # GetBranches
37 # use Net::LDAP qw(:all);
39 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
41 # set the version for version checking
46 C4::Auth - Authenticates Koha users
55 my ($template, $borrowernumber, $cookie)
56 = get_template_and_user(
58 template_name => "opac-main.tmpl",
62 flagsrequired => {borrow => 1},
74 The main function of this module is to provide
75 authentification. However the get_template_and_user function has
76 been provided so that a users login information is passed along
77 automatically. This gets loaded into the template.
88 &get_template_and_user
94 =item get_template_and_user
96 my ($template, $borrowernumber, $cookie)
97 = get_template_and_user(
99 template_name => "opac-main.tmpl",
102 authnotrequired => 1,
103 flagsrequired => {borrow => 1},
107 This call passes the C<query>, C<flagsrequired> and C<authnotrequired>
108 to C<&checkauth> (in this module) to perform authentification.
109 See C<&checkauth> for an explanation of these parameters.
111 The C<template_name> is then used to find the correct template for
112 the page. The authenticated users details are loaded onto the
113 template in the HTML::Template LOOP variable C<USER_INFO>. Also the
114 C<sessionID> is passed to the template. This can be used in templates
115 if cookies are disabled. It needs to be put as and input to every
118 More information on the C<gettemplate> sub can be found in the
123 sub get_template_and_user {
126 gettemplate( $in->{'template_name'}, $in->{'type'}, $in->{'query'} );
127 my ( $user, $cookie, $sessionID, $flags ) = checkauth(
129 $in->{'authnotrequired'},
130 $in->{'flagsrequired'},
132 ) unless ($in->{'template_name'}=~/maintenance/);
135 my $insecure = C4::Context->preference('insecure');
136 if ($user or $insecure) {
138 # load the template variables for stylesheets and JavaScript
139 $template->param( css_libs => $in->{'css_libs'} );
140 $template->param( css_module => $in->{'css_module'} );
141 $template->param( css_page => $in->{'css_page'} );
142 $template->param( css_widgets => $in->{'css_widgets'} );
144 $template->param( js_libs => $in->{'js_libs'} );
145 $template->param( js_module => $in->{'js_module'} );
146 $template->param( js_page => $in->{'js_page'} );
147 $template->param( js_widgets => $in->{'js_widgets'} );
150 $template->param( loggedinusername => $user );
151 $template->param( sessionID => $sessionID );
153 $borrowernumber = getborrowernumber($user);
154 my ( $borr, $alternativeflags ) =
155 GetMemberDetails( $borrowernumber );
158 $template->param( "USER_INFO" => \@bordat );
160 # We are going to use the $flags returned by checkauth
161 # to create the template's parameters that will indicate
162 # which menus the user can access.
163 if (( $flags && $flags->{superlibrarian}==1) or $insecure==1) {
164 $template->param( CAN_user_circulate => 1 );
165 $template->param( CAN_user_catalogue => 1 );
166 $template->param( CAN_user_parameters => 1 );
167 $template->param( CAN_user_borrowers => 1 );
168 $template->param( CAN_user_permission => 1 );
169 $template->param( CAN_user_reserveforothers => 1 );
170 $template->param( CAN_user_borrow => 1 );
171 $template->param( CAN_user_editcatalogue => 1 );
172 $template->param( CAN_user_updatecharge => 1 );
173 $template->param( CAN_user_acquisition => 1 );
174 $template->param( CAN_user_management => 1 );
175 $template->param( CAN_user_tools => 1 );
176 $template->param( CAN_user_editauthorities => 1 );
177 $template->param( CAN_user_serials => 1 );
178 $template->param( CAN_user_reports => 1 );
181 if ( $flags && $flags->{circulate} == 1 ) {
182 $template->param( CAN_user_circulate => 1 );
185 if ( $flags && $flags->{catalogue} == 1 ) {
186 $template->param( CAN_user_catalogue => 1 );
189 if ( $flags && $flags->{parameters} == 1 ) {
190 $template->param( CAN_user_parameters => 1 );
191 $template->param( CAN_user_management => 1 );
194 if ( $flags && $flags->{borrowers} == 1 ) {
195 $template->param( CAN_user_borrowers => 1 );
198 if ( $flags && $flags->{permissions} == 1 ) {
199 $template->param( CAN_user_permission => 1 );
202 if ( $flags && $flags->{reserveforothers} == 1 ) {
203 $template->param( CAN_user_reserveforothers => 1 );
206 if ( $flags && $flags->{borrow} == 1 ) {
207 $template->param( CAN_user_borrow => 1 );
210 if ( $flags && $flags->{editcatalogue} == 1 ) {
211 $template->param( CAN_user_editcatalogue => 1 );
214 if ( $flags && $flags->{updatecharges} == 1 ) {
215 $template->param( CAN_user_updatecharge => 1 );
218 if ( $flags && $flags->{acquisition} == 1 ) {
219 $template->param( CAN_user_acquisition => 1 );
222 if ( $flags && $flags->{tools} == 1 ) {
223 $template->param( CAN_user_tools => 1 );
226 if ( $flags && $flags->{editauthorities} == 1 ) {
227 $template->param( CAN_user_editauthorities => 1 );
230 if ( $flags && $flags->{serials} == 1 ) {
231 $template->param( CAN_user_serials => 1 );
234 if ( $flags && $flags->{reports} == 1 ) {
235 $template->param( CAN_user_reports => 1 );
238 if ( $in->{'type'} eq "intranet" ) {
240 intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
241 intranetstylesheet => C4::Context->preference("intranetstylesheet"),
242 IntranetNav => C4::Context->preference("IntranetNav"),
243 intranetuserjs => C4::Context->preference("intranetuserjs"),
244 TemplateEncoding => C4::Context->preference("TemplateEncoding"),
245 AmazonContent => C4::Context->preference("AmazonContent"),
246 LibraryName => C4::Context->preference("LibraryName"),
247 LoginBranchcode => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
248 LoginBranchname => (C4::Context->userenv?C4::Context->userenv->{"branchname"}:"insecure"),
249 LoginFirstname => (C4::Context->userenv?C4::Context->userenv->{"firstname"}:"Bel"),
250 LoginSurname => C4::Context->userenv?C4::Context->userenv->{"surname"}:"Inconnu",
251 AutoLocation => C4::Context->preference("AutoLocation"),
252 hide_marc => C4::Context->preference("hide_marc"),
253 patronimages => C4::Context->preference("patronimages"),
254 "BiblioDefaultView".C4::Context->preference("IntranetBiblioDefaultView") => 1,
255 advancedMARCEditor => C4::Context->preference("advancedMARCEditor"),
256 suggestion => C4::Context->preference("suggestion"),
257 virtualshelves => C4::Context->preference("virtualshelves"),
258 LibraryName => C4::Context->preference("LibraryName"),
259 KohaAdminEmailAddress => "" . C4::Context->preference("KohaAdminEmailAddress"),
260 IntranetmainUserblock => C4::Context->preference("IntranetmainUserblock"),
261 IndependantBranches => C4::Context->preference("IndependantBranches"),
262 CircAutocompl => C4::Context->preference("CircAutocompl"),
263 yuipath => C4::Context->preference("yuipath"),
267 warn "template type should be OPAC, here it is=[" . $in->{'type'} . "]" unless ( $in->{'type'} eq 'opac' );
268 my $LibraryNameTitle = C4::Context->preference("LibraryName");
269 $LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi;
270 $LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg;
272 KohaAdminEmailAddress => "" . C4::Context->preference("KohaAdminEmailAddress"),
273 suggestion => "" . C4::Context->preference("suggestion"),
274 virtualshelves => "" . C4::Context->preference("virtualshelves"),
275 OpacNav => "" . C4::Context->preference("OpacNav"),
276 opacheader => "" . C4::Context->preference("opacheader"),
277 opaccredits => "" . C4::Context->preference("opaccredits"),
278 opacsmallimage => "" . C4::Context->preference("opacsmallimage"),
279 opaclargeimage => "" . C4::Context->preference("opaclargeimage"),
280 opaclayoutstylesheet => "". C4::Context->preference("opaclayoutstylesheet"),
281 opaccolorstylesheet => "". C4::Context->preference("opaccolorstylesheet"),
282 opaclanguagesdisplay => "". C4::Context->preference("opaclanguagesdisplay"),
283 opacuserlogin => "" . C4::Context->preference("opacuserlogin"),
284 opacbookbag => "" . C4::Context->preference("opacbookbag"),
285 TemplateEncoding => "". C4::Context->preference("TemplateEncoding"),
286 AmazonContent => "" . C4::Context->preference("AmazonContent"),
287 LibraryName => "" . C4::Context->preference("LibraryName"),
288 LibraryNameTitle => "" . $LibraryNameTitle,
289 LoginBranchcode => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
290 LoginBranchname => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"",
291 LoginFirstname => (C4::Context->userenv?C4::Context->userenv->{"firstname"}:"Bel"),
292 LoginSurname => C4::Context->userenv?C4::Context->userenv->{"surname"}:"Inconnu",
293 OpacPasswordChange => C4::Context->preference("OpacPasswordChange"),
294 opacreadinghistory => C4::Context->preference("opacreadinghistory"),
295 opacuserjs => C4::Context->preference("opacuserjs"),
296 OpacCloud => C4::Context->preference("OpacCloud"),
297 OpacTopissue => C4::Context->preference("OpacTopissue"),
298 OpacAuthorities => C4::Context->preference("OpacAuthorities"),
299 OpacBrowser => C4::Context->preference("OpacBrowser"),
300 RequestOnOpac => C4::Context->preference("RequestOnOpac"),
301 reviewson => C4::Context->preference("reviewson"),
302 hide_marc => C4::Context->preference("hide_marc"),
303 patronimages => C4::Context->preference("patronimages"),
304 mylibraryfirst => C4::Context->preference("SearchMyLibraryFirst"),
305 "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
308 return ( $template, $borrowernumber, $cookie );
313 ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
315 Verifies that the user is authorized to run this script. If
316 the user is authorized, a (userid, cookie, session-id, flags)
317 quadruple is returned. If the user is not authorized but does
318 not have the required privilege (see $flagsrequired below), it
319 displays an error page and exits. Otherwise, it displays the
320 login page and exits.
322 Note that C<&checkauth> will return if and only if the user
323 is authorized, so it should be called early on, before any
324 unfinished operations (e.g., if you've opened a file, then
325 C<&checkauth> won't close it for you).
327 C<$query> is the CGI object for the script calling C<&checkauth>.
329 The C<$noauth> argument is optional. If it is set, then no
330 authorization is required for the script.
332 C<&checkauth> fetches user and session information from C<$query> and
333 ensures that the user is authorized to run scripts that require
336 The C<$flagsrequired> argument specifies the required privileges
337 the user must have if the username and password are correct.
338 It should be specified as a reference-to-hash; keys in the hash
339 should be the "flags" for the user, as specified in the Members
340 intranet module. Any key specified must correspond to a "flag"
341 in the userflags table. E.g., { circulate => 1 } would specify
342 that the user must have the "circulate" privilege in order to
343 proceed. To make sure that access control is correct, the
344 C<$flagsrequired> parameter must be specified correctly.
346 The C<$type> argument specifies whether the template should be
347 retrieved from the opac or intranet directory tree. "opac" is
348 assumed if it is not specified; however, if C<$type> is specified,
349 "intranet" is assumed if it is not "opac".
351 If C<$query> does not have a valid session ID associated with it
352 (i.e., the user has not logged in) or if the session has expired,
353 C<&checkauth> presents the user with a login page (from the point of
354 view of the original script, C<&checkauth> does not return). Once the
355 user has authenticated, C<&checkauth> restarts the original script
356 (this time, C<&checkauth> returns).
358 The login page is provided using a HTML::Template, which is set in the
359 systempreferences table or at the top of this file. The variable C<$type>
360 selects which template to use, either the opac or the intranet
361 authentification template.
363 C<&checkauth> returns a user ID, a cookie, and a session ID. The
364 cookie should be sent back to the browser; it verifies that the user
371 # warn "Checking Auth";
372 # $authnotrequired will be set for scripts which will run without authentication
373 my $authnotrequired = shift;
374 my $flagsrequired = shift;
376 $type = 'opac' unless $type;
378 my $dbh = C4::Context->dbh;
379 my $timeout = C4::Context->preference('timeout');
380 $timeout = 600 unless $timeout;
383 # If Version syspref is unavailable, it means Koha is beeing installed,
384 # and so we must redirect to OPAC maintenance page or to the WebInstaller
385 #warn "about to check version";
386 unless (C4::Context->preference('Version')) {
387 if ($type ne 'opac') {
388 warn "Install required, redirecting to Installer";
389 print $query->redirect("/cgi-bin/koha/installer/install.pl");
392 warn "OPAC Install required, redirecting to maintenance";
393 print $query->redirect("/cgi-bin/koha/maintenance.pl");
402 my ( $userid, $cookie, $sessionID, $flags );
403 my $logout = $query->param('logout.x');
404 if ( $userid = $ENV{'REMOTE_USER'} ) {
405 # Using Basic Authentication, no cookies required
406 $cookie = $query->cookie(
407 -name => 'CGISESSID',
413 elsif ( $sessionID = $query->cookie("CGISESSID")) {
414 my $storage_method = C4::Context->preference('SessionStorage');
416 if ($storage_method eq 'mysql'){
417 $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
419 elsif ($storage_method eq 'Pg') {
420 $session = new CGI::Session("driver:PostgreSQL", $sessionID, {Handle=>$dbh});
423 # catch all defaults to tmp should work on all systems
424 $session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
426 C4::Context->_new_userenv($sessionID);
428 C4::Context::set_userenv(
429 $session->param('number'), $session->param('id'),
430 $session->param('cardnumber'), $session->param('firstname'),
431 $session->param('surname'), $session->param('branch'),
432 $session->param('branchname'), $session->param('flags'),
433 $session->param('emailaddress'), $session->param('branchprinter')
435 # warn "".$session->param('cardnumber').", ".$session->param('firstname').",
436 # ".$session->param('surname').", ".$session->param('branch');
441 $ip = $session->param('ip');
442 $lasttime = $session->param('lasttime');
443 $userid = $session->param('id');
449 # voluntary logout the user
453 C4::Context->_unset_userenv($sessionID);
456 open L, ">>/tmp/sessionlog";
457 my $time = localtime( time() );
458 printf L "%20s from %16s logged out at %30s (manually).\n", $userid,
463 if ( $lasttime < time() - $timeout ) {
465 $info{'timed_out'} = 1;
467 C4::Context->_unset_userenv($sessionID);
470 open L, ">>/tmp/sessionlog";
471 my $time = localtime( time() );
472 printf L "%20s from %16s logged out at %30s (inactivity).\n",
476 elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
477 # Different ip than originally logged in from
478 $info{'oldip'} = $ip;
479 $info{'newip'} = $ENV{'REMOTE_ADDR'};
480 $info{'different_ip'} = 1;
482 C4::Context->_unset_userenv($sessionID);
485 open L, ">>/tmp/sessionlog";
486 my $time = localtime( time() );
488 "%20s from logged out at %30s (ip changed from %16s to %16s).\n",
489 $userid, $time, $ip, $info{'newip'};
493 $cookie = $query->cookie( CGISESSID => $session->id );
494 $session->param('lasttime',time());
495 $flags = haspermission( $dbh, $userid, $flagsrequired );
500 $info{'nopermission'} = 1;
506 my $storage_method = C4::Context->preference('SessionStorage');
508 if ($storage_method eq 'mysql'){
509 $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
511 elsif ($storage_method eq 'Pg') {
512 $session = new CGI::Session("driver:PostgreSQL", $sessionID, {Handle=>$dbh});
515 # catch all defaults to tmp should work on all systems
516 $session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
521 $sessionID = $session->id;
523 $userid = $query->param('userid');
524 C4::Context->_new_userenv($sessionID);
525 my $password = $query->param('password');
526 C4::Context->_new_userenv($sessionID);
527 my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
529 open L, ">>/tmp/sessionlog";
530 my $time = localtime( time() );
531 printf L "%20s from %16s logged in at %30s.\n", $userid,
532 $ENV{'REMOTE_ADDR'}, $time;
534 $cookie = $query->cookie(CGISESSID => $sessionID);
535 if ( $flags = haspermission( $dbh, $userid, $flagsrequired ) ) {
539 $info{'nopermission'} = 1;
540 C4::Context->_unset_userenv($sessionID);
542 if ( $return == 1 ) {
544 $borrowernumber, $firstname, $surname,
545 $userflags, $branchcode, $branchname,
546 $branchprinter, $emailaddress
550 "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=?"
552 $sth->execute($userid);
554 $borrowernumber, $firstname, $surname,
555 $userflags, $branchcode, $branchname,
556 $branchprinter, $emailaddress
561 # warn "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
562 unless ( $sth->rows ) {
565 "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=?"
567 $sth->execute($cardnumber);
569 $borrowernumber, $firstname, $surname,
570 $userflags, $branchcode, $branchname,
571 $branchprinter, $emailaddress
576 # warn "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress";
577 unless ( $sth->rows ) {
578 $sth->execute($userid);
580 $borrowernumber, $firstname, $surname, $userflags,
581 $branchcode, $branchname, $branchprinter, $emailaddress
588 # 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.
589 my $ip = $ENV{'REMOTE_ADDR'};
590 # if they specify at login, use that
591 if ($query->param('branch')) {
592 $branchcode = $query->param('branch');
593 $branchname = GetBranchName($branchcode);
595 my $branches = GetBranches();
597 foreach my $br ( keys %$branches ) {
598 # now we work with the treatment of ip
599 my $domain = $branches->{$br}->{'branchip'};
600 if ( $domain && $ip =~ /^$domain/ ) {
601 $branchcode = $branches->{$br}->{'branchcode'};
603 # new op dev : add the branchprinter and branchname in the cookie
604 $branchprinter = $branches->{$br}->{'branchprinter'};
605 $branchname = $branches->{$br}->{'branchname'};
608 $session->param('number',$borrowernumber);
609 $session->param('id',$userid);
610 $session->param('cardnumber',$cardnumber);
611 $session->param('firstname',$firstname);
612 $session->param('surname',$surname);
613 $session->param('branch',$branchcode);
614 $session->param('branchname',$branchname);
615 $session->param('flags',$userflags);
616 $session->param('emailaddress',$emailaddress);
617 $session->param('ip',$session->remote_addr());
618 $session->param('lasttime',time());
619 # warn "".$session->param('cardnumber').", ".$session->param('firstname').",
620 # ".$session->param('surname').", ".$session->param('branch');
622 elsif ( $return == 2 ) {
623 #We suppose the user is the superlibrarian
624 $session->param('number',0);
625 $session->param('id',C4::Context->config('user'));
626 $session->param('cardnumber',C4::Context->config('user'));
627 $session->param('firstname',C4::Context->config('user'));
628 $session->param('surname',C4::Context->config('user'));
629 $session->param('branch','NO_LIBRARY_SET');
630 $session->param('branchname','NO_LIBRARY_SET');
631 $session->param('flags',1);
632 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
633 $session->param('ip',$session->remote_addr());
634 $session->param('lasttime',time());
637 C4::Context::set_userenv(
638 $session->param('number'), $session->param('id'),
639 $session->param('cardnumber'), $session->param('firstname'),
640 $session->param('surname'), $session->param('branch'),
641 $session->param('branchname'), $session->param('flags'),
642 $session->param('emailaddress'), $session->param('branchprinter')
649 $info{'invalid_username_or_password'} = 1;
650 C4::Context->_unset_userenv($sessionID);
654 my $insecure = C4::Context->boolean_preference('insecure');
656 # finished authentification, now respond
657 if ( $loggedin || $authnotrequired || ( defined($insecure) && $insecure ) )
661 $cookie = $query->cookie( CGISESSID => ''
664 return ( $userid, $cookie, $sessionID, $flags );
670 # AUTH rejected, show the login/password template, after checking the DB.
674 # get the inputs from the incoming query
676 foreach my $name ( param $query) {
677 (next) if ( $name eq 'userid' || $name eq 'password' );
678 my $value = $query->param($name);
679 push @inputs, { name => $name, value => $value };
681 # get the branchloop, which we need for authentication
682 my $branches = GetBranches();
684 for my $branch_hash (keys %$branches) {
685 push @branch_loop, {branchcode => "$branch_hash", branchname => $branches->{$branch_hash}->{'branchname'}, };
688 # check that database and koha version are the same
689 # there is no DB version, it's a fresh install,
690 # go to web installer
691 # there is a DB version, compare it to the code version
692 my $kohaversion=C4::Context::KOHAVERSION;
693 # remove the 3 last . to have a Perl number
694 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
695 # warn "kohaversion : $kohaversion";
696 if (C4::Context->preference('Version') < $kohaversion){
697 if ($type ne 'opac'){
698 warn "Database update needed, redirecting to Installer. Database is ".C4::Context->preference('Version')." and Koha is : ".C4::Context->config("kohaversion");
699 print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
701 warn "OPAC :Database update needed, redirecting to maintenance. Database is ".C4::Context->preference('Version')." and Koha is : ".C4::Context->config("kohaversion");
702 print $query->redirect("/cgi-bin/koha/maintenance.pl");
707 if ( $type eq 'opac' ) {
708 $template_name = "opac-auth.tmpl";
711 $template_name = "auth.tmpl";
713 my $template = gettemplate( $template_name, $type, $query );
714 $template->param(branchloop => \@branch_loop,);
718 suggestion => C4::Context->preference("suggestion"),
719 virtualshelves => C4::Context->preference("virtualshelves"),
720 opaclargeimage => C4::Context->preference("opaclargeimage"),
721 LibraryName => C4::Context->preference("LibraryName"),
722 OpacNav => C4::Context->preference("OpacNav"),
723 opaccredits => C4::Context->preference("opaccredits"),
724 opacreadinghistory => C4::Context->preference("opacreadinghistory"),
725 opacsmallimage => C4::Context->preference("opacsmallimage"),
726 opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
727 opaccolorstylesheet => C4::Context->preference("opaccolorstylesheet"),
728 opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
729 opacuserjs => C4::Context->preference("opacuserjs"),
731 intranetcolorstylesheet =>
732 C4::Context->preference("intranetcolorstylesheet"),
733 intranetstylesheet => C4::Context->preference("intranetstylesheet"),
734 IntranetNav => C4::Context->preference("IntranetNav"),
735 intranetuserjs => C4::Context->preference("intranetuserjs"),
736 TemplateEncoding => C4::Context->preference("TemplateEncoding"),
737 IndependantBranches => C4::Context->preference("IndependantBranches"),
738 AutoLocation => C4::Context->preference("AutoLocation"),
740 $template->param( loginprompt => 1 ) unless $info{'nopermission'};
742 my $self_url = $query->url( -absolute => 1 );
745 LibraryName => => C4::Context->preference("LibraryName"),
747 $template->param( \%info );
748 # $cookie = $query->cookie(CGISESSID => $session->id
750 print $query->header(
751 -type => 'text/html',
761 ($status, $cookie, $sessionId) = check_api_auth($query, $userflags);
763 Given a CGI query containing the parameters 'userid' and 'password' and/or a session
764 cookie, determine if the user has the privileges specified by C<$userflags>.
766 C<check_api_auth> is is meant for authenticating users of web services, and
767 consequently will always return and will not attempt to redirect the user
770 If a valid session cookie is already present, check_api_auth will return a status
771 of "ok", the cookie, and the Koha session ID.
773 If no session cookie is present, check_api_auth will check the 'userid' and 'password
774 parameters and create a session cookie and Koha session if the supplied credentials
777 Possible return values in C<$status> are:
781 =item "ok" -- user authenticated; C<$cookie> and C<$sessionid> have valid values.
783 =item "failed" -- credentials are not correct; C<$cookie> and C<$sessionid> are undef
785 =item "maintenance" -- DB is in maintenance mode; no login possible at the moment
787 =item "expired -- session cookie has expired; API user should resubmit userid and password
795 my $flagsrequired = shift;
797 my $dbh = C4::Context->dbh;
798 my $timeout = C4::Context->preference('timeout');
799 $timeout = 600 unless $timeout;
801 unless (C4::Context->preference('Version')) {
802 # database has not been installed yet
803 return ("maintenance", undef, undef);
805 my $kohaversion=C4::Context::KOHAVERSION;
806 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
807 if (C4::Context->preference('Version') < $kohaversion) {
808 # database in need of version update; assume that
809 # no API should be called while databsae is in
811 return ("maintenance", undef, undef);
814 # FIXME -- most of what follows is a copy-and-paste
815 # of code from checkauth. There is an obvious need
816 # for refactoring to separate the various parts of
817 # the authentication code, but as of 2007-11-19 this
818 # is deferred so as to not introduce bugs into the
819 # regular authentication code for Koha 3.0.
821 # see if we have a valid session cookie already
822 # however, if a userid parameter is present (i.e., from
823 # a form submission, assume that any current cookie
825 my $sessionID = undef;
826 unless ($query->param('userid')) {
827 $sessionID = $query->cookie("CGISESSID");
830 my $storage_method = C4::Context->preference('SessionStorage');
832 if ($storage_method eq 'mysql'){
833 $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
835 elsif ($storage_method eq 'Pg') {
836 $session = new CGI::Session("driver:PostgreSQL", $sessionID, {Handle=>$dbh});
839 # catch all defaults to tmp should work on all systems
840 $session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
842 C4::Context->_new_userenv($sessionID);
844 C4::Context::set_userenv(
845 $session->param('number'), $session->param('id'),
846 $session->param('cardnumber'), $session->param('firstname'),
847 $session->param('surname'), $session->param('branch'),
848 $session->param('branchname'), $session->param('flags'),
849 $session->param('emailaddress'), $session->param('branchprinter')
852 my $ip = $session->param('ip');
853 my $lasttime = $session->param('lasttime');
854 my $userid = $session->param('id');
855 if ( $lasttime < time() - $timeout ) {
858 C4::Context->_unset_userenv($sessionID);
861 return ("expired", undef, undef);
862 } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
865 C4::Context->_unset_userenv($sessionID);
868 return ("expired", undef, undef);
870 my $cookie = $query->cookie( CGISESSID => $session->id );
871 $session->param('lasttime',time());
872 my $flags = haspermission( $dbh, $userid, $flagsrequired );
874 return ("ok", $cookie, $sessionID);
877 C4::Context->_unset_userenv($sessionID);
880 return ("failed", undef, undef);
884 return ("expired", undef, undef);
888 my $userid = $query->param('userid');
889 my $password = $query->param('password');
890 unless ($userid and $password) {
891 # caller did something wrong, fail the authenticateion
892 return ("failed", undef, undef);
894 my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
895 if ($return and haspermission( $dbh, $userid, $flagsrequired)) {
896 my $storage_method = C4::Context->preference('SessionStorage');
898 if ($storage_method eq 'mysql'){
899 $session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
900 } elsif ($storage_method eq 'Pg') {
901 $session = new CGI::Session("driver:PostgreSQL", $sessionID, {Handle=>$dbh});
903 # catch all defaults to tmp should work on all systems
904 $session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
906 return ("failed", undef, undef) unless $session;
908 my $sessionID = $session->id;
909 C4::Context->_new_userenv($sessionID);
910 my $cookie = $query->cookie(CGISESSID => $sessionID);
911 if ( $return == 1 ) {
913 $borrowernumber, $firstname, $surname,
914 $userflags, $branchcode, $branchname,
915 $branchprinter, $emailaddress
919 "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=?"
921 $sth->execute($userid);
923 $borrowernumber, $firstname, $surname,
924 $userflags, $branchcode, $branchname,
925 $branchprinter, $emailaddress
926 ) = $sth->fetchrow if ( $sth->rows );
928 unless ($sth->rows ) {
929 my $sth = $dbh->prepare(
930 "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=?"
932 $sth->execute($cardnumber);
934 $borrowernumber, $firstname, $surname,
935 $userflags, $branchcode, $branchname,
936 $branchprinter, $emailaddress
937 ) = $sth->fetchrow if ( $sth->rows );
939 unless ( $sth->rows ) {
940 $sth->execute($userid);
942 $borrowernumber, $firstname, $surname, $userflags,
943 $branchcode, $branchname, $branchprinter, $emailaddress
944 ) = $sth->fetchrow if ( $sth->rows );
948 my $ip = $ENV{'REMOTE_ADDR'};
949 # if they specify at login, use that
950 if ($query->param('branch')) {
951 $branchcode = $query->param('branch');
952 $branchname = GetBranchName($branchcode);
954 my $branches = GetBranches();
956 foreach my $br ( keys %$branches ) {
957 # now we work with the treatment of ip
958 my $domain = $branches->{$br}->{'branchip'};
959 if ( $domain && $ip =~ /^$domain/ ) {
960 $branchcode = $branches->{$br}->{'branchcode'};
962 # new op dev : add the branchprinter and branchname in the cookie
963 $branchprinter = $branches->{$br}->{'branchprinter'};
964 $branchname = $branches->{$br}->{'branchname'};
967 $session->param('number',$borrowernumber);
968 $session->param('id',$userid);
969 $session->param('cardnumber',$cardnumber);
970 $session->param('firstname',$firstname);
971 $session->param('surname',$surname);
972 $session->param('branch',$branchcode);
973 $session->param('branchname',$branchname);
974 $session->param('flags',$userflags);
975 $session->param('emailaddress',$emailaddress);
976 $session->param('ip',$session->remote_addr());
977 $session->param('lasttime',time());
978 } elsif ( $return == 2 ) {
979 #We suppose the user is the superlibrarian
980 $session->param('number',0);
981 $session->param('id',C4::Context->config('user'));
982 $session->param('cardnumber',C4::Context->config('user'));
983 $session->param('firstname',C4::Context->config('user'));
984 $session->param('surname',C4::Context->config('user'));
985 $session->param('branch','NO_LIBRARY_SET');
986 $session->param('branchname','NO_LIBRARY_SET');
987 $session->param('flags',1);
988 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
989 $session->param('ip',$session->remote_addr());
990 $session->param('lasttime',time());
992 C4::Context::set_userenv(
993 $session->param('number'), $session->param('id'),
994 $session->param('cardnumber'), $session->param('firstname'),
995 $session->param('surname'), $session->param('branch'),
996 $session->param('branchname'), $session->param('flags'),
997 $session->param('emailaddress'), $session->param('branchprinter')
999 return ("ok", $cookie, $sessionID);
1001 return ("failed", undef, undef);
1008 my ( $dbh, $userid, $password ) = @_;
1013 "select password,cardnumber,borrowernumber,userid,firstname,surname,branchcode,flags from borrowers where userid=?"
1015 $sth->execute($userid);
1017 my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
1018 $surname, $branchcode, $flags )
1020 if ( md5_base64($password) eq $md5password ) {
1022 C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
1023 $firstname, $surname, $branchcode, $flags );
1024 return 1, $cardnumber;
1029 "select password,cardnumber,borrowernumber,userid, firstname,surname,branchcode,flags from borrowers where cardnumber=?"
1031 $sth->execute($userid);
1033 my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
1034 $surname, $branchcode, $flags )
1036 if ( md5_base64($password) eq $md5password ) {
1038 C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
1039 $firstname, $surname, $branchcode, $flags );
1043 if ( $userid && $userid eq C4::Context->config('user')
1044 && "$password" eq C4::Context->config('pass') )
1047 # Koha superuser account
1048 # C4::Context->set_userenv(0,0,C4::Context->config('user'),C4::Context->config('user'),C4::Context->config('user'),"",1);
1051 if ( $userid && $userid eq 'demo'
1052 && "$password" eq 'demo'
1053 && C4::Context->config('demo') )
1056 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
1057 # some features won't be effective : modify systempref, modify MARC structure,
1064 my $cardnumber = shift;
1067 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE cardnumber=?");
1068 $sth->execute($cardnumber);
1069 my ($flags) = $sth->fetchrow;
1070 $flags = 0 unless $flags;
1071 $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
1074 while ( my ( $bit, $flag, $defaulton ) = $sth->fetchrow ) {
1075 if ( ( $flags & ( 2**$bit ) ) || $defaulton ) {
1076 $userflags->{$flag} = 1;
1079 $userflags->{$flag} = 0;
1086 my ( $dbh, $userid, $flagsrequired ) = @_;
1087 my $sth = $dbh->prepare("SELECT cardnumber FROM borrowers WHERE userid=?");
1088 $sth->execute($userid);
1089 my ($cardnumber) = $sth->fetchrow;
1090 ($cardnumber) || ( $cardnumber = $userid );
1091 my $flags = getuserflags( $cardnumber, $dbh );
1093 if ( $userid eq C4::Context->config('user') ) {
1095 # Super User Account from /etc/koha.conf
1096 $flags->{'superlibrarian'} = 1;
1098 if ( $userid eq 'demo' && C4::Context->config('demo') ) {
1100 # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
1101 $flags->{'superlibrarian'} = 1;
1103 return $flags if $flags->{superlibrarian};
1104 foreach ( keys %$flagsrequired ) {
1105 return $flags if $flags->{$_};
1110 sub getborrowernumber {
1112 my $dbh = C4::Context->dbh;
1113 for my $field ( 'userid', 'cardnumber' ) {
1115 $dbh->prepare("select borrowernumber from borrowers where $field=?");
1116 $sth->execute($userid);
1118 my ($bnumber) = $sth->fetchrow;
1125 END { } # module clean-up code here (global destructor)