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
34 use C4::VirtualShelves;
37 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap);
40 $VERSION = 3.02; # set version for version checking
41 $debug = $ENV{DEBUG} || 0 ;
43 @EXPORT = qw(&checkauth &get_template_and_user);
44 @EXPORT_OK = qw(&check_api_auth &get_session &check_cookie_auth &checkpw &get_all_subpermissions &get_user_subpermissions);
45 %EXPORT_TAGS = (EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)]);
46 $ldap = C4::Context->config('useldapserver') || 0;
48 require C4::Auth_with_ldap; # no import
49 import C4::Auth_with_ldap qw(checkpw_ldap);
55 C4::Auth - Authenticates Koha users
65 my ($template, $borrowernumber, $cookie)
66 = get_template_and_user(
68 template_name => "opac-main.tmpl",
72 flagsrequired => {borrow => 1, catalogue => '*', tools => 'import_patrons' },
76 output_html_with_http_headers $query, $cookie, $template->output;
80 The main function of this module is to provide
81 authentification. However the get_template_and_user function has
82 been provided so that a users login information is passed along
83 automatically. This gets loaded into the template.
89 =item get_template_and_user
91 my ($template, $borrowernumber, $cookie)
92 = get_template_and_user(
94 template_name => "opac-main.tmpl",
98 flagsrequired => {borrow => 1, catalogue => '*', tools => 'import_patrons' },
102 This call passes the C<query>, C<flagsrequired> and C<authnotrequired>
103 to C<&checkauth> (in this module) to perform authentification.
104 See C<&checkauth> for an explanation of these parameters.
106 The C<template_name> is then used to find the correct template for
107 the page. The authenticated users details are loaded onto the
108 template in the HTML::Template LOOP variable C<USER_INFO>. Also the
109 C<sessionID> is passed to the template. This can be used in templates
110 if cookies are disabled. It needs to be put as and input to every
113 More information on the C<gettemplate> sub can be found in the
118 sub get_template_and_user {
121 gettemplate( $in->{'template_name'}, $in->{'type'}, $in->{'query'} );
122 my ( $user, $cookie, $sessionID, $flags ) = checkauth(
124 $in->{'authnotrequired'},
125 $in->{'flagsrequired'},
127 ) unless ($in->{'template_name'}=~/maintenance/);
130 my $insecure = C4::Context->preference('insecure');
131 if ($user or $insecure) {
133 # load the template variables for stylesheets and JavaScript
134 $template->param( css_libs => $in->{'css_libs'} );
135 $template->param( css_module => $in->{'css_module'} );
136 $template->param( css_page => $in->{'css_page'} );
137 $template->param( css_widgets => $in->{'css_widgets'} );
139 $template->param( js_libs => $in->{'js_libs'} );
140 $template->param( js_module => $in->{'js_module'} );
141 $template->param( js_page => $in->{'js_page'} );
142 $template->param( js_widgets => $in->{'js_widgets'} );
145 $template->param( loggedinusername => $user );
146 $template->param( sessionID => $sessionID );
148 my ($total, $pubshelves, $barshelves) = C4::Context->get_shelves_userenv();
149 if (defined($pubshelves)) {
150 $template->param( pubshelves => scalar (@$pubshelves),
151 pubshelvesloop => $pubshelves,
153 $template->param( pubtotal => $total->{'pubtotal'}, ) if ($total->{'pubtotal'} > scalar (@$pubshelves));
155 if (defined($barshelves)) {
156 $template->param( barshelves => scalar (@$barshelves),
157 barshelvesloop => $barshelves,
159 $template->param( bartotal => $total->{'bartotal'}, ) if ($total->{'bartotal'} > scalar (@$barshelves));
162 $borrowernumber = getborrowernumber($user);
163 my ( $borr ) = GetMemberDetails( $borrowernumber );
166 $template->param( "USER_INFO" => \@bordat );
168 my $all_perms = get_all_subpermissions();
170 my @flagroots = qw(circulate catalogue parameters borrowers permissions reserveforothers borrow
171 editcatalogue updatecharges management tools editauthorities serials reports);
172 # We are going to use the $flags returned by checkauth
173 # to create the template's parameters that will indicate
174 # which menus the user can access.
175 if (( $flags && $flags->{superlibrarian}==1) or $insecure==1) {
176 $template->param( CAN_user_circulate => 1 );
177 $template->param( CAN_user_catalogue => 1 );
178 $template->param( CAN_user_parameters => 1 );
179 $template->param( CAN_user_borrowers => 1 );
180 $template->param( CAN_user_permissions => 1 );
181 $template->param( CAN_user_reserveforothers => 1 );
182 $template->param( CAN_user_borrow => 1 );
183 $template->param( CAN_user_editcatalogue => 1 );
184 $template->param( CAN_user_updatecharges => 1 );
185 $template->param( CAN_user_acquisition => 1 );
186 $template->param( CAN_user_management => 1 );
187 $template->param( CAN_user_tools => 1 );
188 $template->param( CAN_user_editauthorities => 1 );
189 $template->param( CAN_user_serials => 1 );
190 $template->param( CAN_user_reports => 1 );
191 $template->param( CAN_user_staffaccess => 1 );
192 foreach my $module (keys %$all_perms) {
193 foreach my $subperm (keys %{ $all_perms->{$module} }) {
194 $template->param( "CAN_user_${module}_${subperm}" => 1 );
199 if (C4::Context->preference('GranularPermissions')) {
201 foreach my $module (keys %$all_perms) {
202 if ( $flags->{$module} == 1) {
203 foreach my $subperm (keys %{ $all_perms->{$module} }) {
204 $template->param( "CAN_user_${module}_${subperm}" => 1 );
206 } elsif ( ref($flags->{$module}) ) {
207 foreach my $subperm (keys %{ $flags->{$module} } ) {
208 $template->param( "CAN_user_${module}_${subperm}" => 1 );
214 foreach my $module (keys %$all_perms) {
215 foreach my $subperm (keys %{ $all_perms->{$module} }) {
216 $template->param( "CAN_user_${module}_${subperm}" => 1 );
222 foreach my $module (keys %$flags) {
223 if ( $flags->{$module} == 1 or ref($flags->{$module}) ) {
224 $template->param( "CAN_user_$module" => 1 );
225 if ($module eq "parameters") {
226 $template->param( CAN_user_management => 1 );
232 else { # if this is an anonymous session, setup to display public lists...
234 # load the template variables for stylesheets and JavaScript
235 $template->param( css_libs => $in->{'css_libs'} );
236 $template->param( css_module => $in->{'css_module'} );
237 $template->param( css_page => $in->{'css_page'} );
238 $template->param( css_widgets => $in->{'css_widgets'} );
240 $template->param( js_libs => $in->{'js_libs'} );
241 $template->param( js_module => $in->{'js_module'} );
242 $template->param( js_page => $in->{'js_page'} );
243 $template->param( js_widgets => $in->{'js_widgets'} );
245 $template->param( sessionID => $sessionID );
247 my ($total, $pubshelves) = C4::Context->get_shelves_userenv(); # an anonymous user has no 'barshelves'...
248 if (defined(($pubshelves))) {
249 $template->param( pubshelves => scalar (@$pubshelves),
250 pubshelvesloop => $pubshelves,
252 $template->param( pubtotal => $total->{'pubtotal'}, ) if ($total->{'pubtotal'} > scalar (@$pubshelves));
257 # these template parameters are set the same regardless of $in->{'type'}
259 "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
260 EnhancedMessagingPreferences => C4::Context->preference('EnhancedMessagingPreferences'),
261 GoogleJackets => C4::Context->preference("GoogleJackets"),
262 KohaAdminEmailAddress => "" . C4::Context->preference("KohaAdminEmailAddress"),
263 LoginBranchcode => (C4::Context->userenv?C4::Context->userenv->{"branch"}:"insecure"),
264 LoginFirstname => (C4::Context->userenv?C4::Context->userenv->{"firstname"}:"Bel"),
265 LoginSurname => C4::Context->userenv?C4::Context->userenv->{"surname"}:"Inconnu",
266 TagsEnabled => C4::Context->preference("TagsEnabled"),
267 hide_marc => C4::Context->preference("hide_marc"),
268 dateformat => C4::Context->preference("dateformat"),
269 'item-level_itypes' => C4::Context->preference('item-level_itypes'),
270 patronimages => C4::Context->preference("patronimages"),
271 singleBranchMode => C4::Context->preference("singleBranchMode"),
274 if ( $in->{'type'} eq "intranet" ) {
276 AmazonContent => C4::Context->preference("AmazonContent"),
277 AmazonSimilarItems => C4::Context->preference("AmazonSimilarItems"),
278 AutoLocation => C4::Context->preference("AutoLocation"),
279 "BiblioDefaultView".C4::Context->preference("IntranetBiblioDefaultView") => 1,
280 CircAutocompl => C4::Context->preference("CircAutocompl"),
281 FRBRizeEditions => C4::Context->preference("FRBRizeEditions"),
282 IndependantBranches => C4::Context->preference("IndependantBranches"),
283 IntranetNav => C4::Context->preference("IntranetNav"),
284 IntranetmainUserblock => C4::Context->preference("IntranetmainUserblock"),
285 LibraryName => C4::Context->preference("LibraryName"),
286 LoginBranchname => (C4::Context->userenv?C4::Context->userenv->{"branchname"}:"insecure"),
287 TemplateEncoding => C4::Context->preference("TemplateEncoding"),
288 advancedMARCEditor => C4::Context->preference("advancedMARCEditor"),
289 canreservefromotherbranches => C4::Context->preference('canreservefromotherbranches'),
290 intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
291 intranetreadinghistory => C4::Context->preference("intranetreadinghistory"),
292 intranetstylesheet => C4::Context->preference("intranetstylesheet"),
293 intranetuserjs => C4::Context->preference("intranetuserjs"),
294 noItemTypeImages => C4::Context->preference("noItemTypeImages"),
295 suggestion => C4::Context->preference("suggestion"),
296 virtualshelves => C4::Context->preference("virtualshelves"),
300 warn "template type should be OPAC, here it is=[" . $in->{'type'} . "]" unless ( $in->{'type'} eq 'opac' );
301 my $LibraryNameTitle = C4::Context->preference("LibraryName");
302 $LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi;
303 $LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg;
305 AmazonContent => "" . C4::Context->preference("AmazonContent"),
306 AnonSuggestions => "" . C4::Context->preference("AnonSuggestions"),
307 AuthorisedValueImages => C4::Context->preference("AuthorisedValueImages"),
308 LibraryName => "" . C4::Context->preference("LibraryName"),
309 LibraryNameTitle => "" . $LibraryNameTitle,
310 LoginBranchname => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"",
311 OPACAmazonSimilarItems => "" . C4::Context->preference("OPACAmazonSimilarItems"),
312 OPACFRBRizeEditions => C4::Context->preference("OPACFRBRizeEditions"),
313 OPACItemHolds => C4::Context->preference("OPACItemHolds"),
314 OPACShelfBrowser => "". C4::Context->preference("OPACShelfBrowser"),
315 OPACURLOpenInNewWindow => "" . C4::Context->preference("OPACURLOpenInNewWindow"),
316 OPACUserCSS => "". C4::Context->preference("OPACUserCSS"),
317 OPACViewOthersSuggestions => "" . C4::Context->preference("OPACViewOthersSuggestions"),
318 OpacAuthorities => C4::Context->preference("OpacAuthorities"),
319 OPACBaseURL => ($in->{'query'}->https() ? "https://" : "http://") .
320 $ENV{'SERVER_NAME'} .
321 ($ENV{'SERVER_PORT'} eq ($in->{'query'}->https() ? "443" : "80") ? '' : ":$ENV{'SERVER_PORT'}"),
322 OpacBrowser => C4::Context->preference("OpacBrowser"),
323 OpacCloud => C4::Context->preference("OpacCloud"),
324 OpacMainUserBlock => "" . C4::Context->preference("OpacMainUserBlock"),
325 OpacNav => "" . C4::Context->preference("OpacNav"),
326 OpacPasswordChange => C4::Context->preference("OpacPasswordChange"),
327 OpacTopissue => C4::Context->preference("OpacTopissue"),
328 RequestOnOpac => C4::Context->preference("RequestOnOpac"),
329 TemplateEncoding => "". C4::Context->preference("TemplateEncoding"),
330 'Version' => C4::Context->preference('Version'),
331 XSLTDetailsDisplay => C4::Context->preference("XSLTDetailsDisplay"),
332 XSLTResultsDisplay => C4::Context->preference("XSLTResultsDisplay"),
333 hidelostitems => C4::Context->preference("hidelostitems"),
334 mylibraryfirst => C4::Context->preference("SearchMyLibraryFirst"),
335 opacbookbag => "" . C4::Context->preference("opacbookbag"),
336 opaccolorstylesheet => "". C4::Context->preference("opaccolorstylesheet"),
337 opaccredits => "" . C4::Context->preference("opaccredits"),
338 opacheader => "" . C4::Context->preference("opacheader"),
339 opaclanguagesdisplay => "". C4::Context->preference("opaclanguagesdisplay"),
340 opaclayoutstylesheet => "". C4::Context->preference("opaclayoutstylesheet"),
341 opacreadinghistory => C4::Context->preference("opacreadinghistory"),
342 opacsmallimage => "" . C4::Context->preference("opacsmallimage"),
343 opacuserjs => C4::Context->preference("opacuserjs"),
344 opacuserlogin => "" . C4::Context->preference("opacuserlogin"),
345 reviewson => C4::Context->preference("reviewson"),
346 suggestion => "" . C4::Context->preference("suggestion"),
347 virtualshelves => "" . C4::Context->preference("virtualshelves"),
350 return ( $template, $borrowernumber, $cookie, $flags);
355 ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
357 Verifies that the user is authorized to run this script. If
358 the user is authorized, a (userid, cookie, session-id, flags)
359 quadruple is returned. If the user is not authorized but does
360 not have the required privilege (see $flagsrequired below), it
361 displays an error page and exits. Otherwise, it displays the
362 login page and exits.
364 Note that C<&checkauth> will return if and only if the user
365 is authorized, so it should be called early on, before any
366 unfinished operations (e.g., if you've opened a file, then
367 C<&checkauth> won't close it for you).
369 C<$query> is the CGI object for the script calling C<&checkauth>.
371 The C<$noauth> argument is optional. If it is set, then no
372 authorization is required for the script.
374 C<&checkauth> fetches user and session information from C<$query> and
375 ensures that the user is authorized to run scripts that require
378 The C<$flagsrequired> argument specifies the required privileges
379 the user must have if the username and password are correct.
380 It should be specified as a reference-to-hash; keys in the hash
381 should be the "flags" for the user, as specified in the Members
382 intranet module. Any key specified must correspond to a "flag"
383 in the userflags table. E.g., { circulate => 1 } would specify
384 that the user must have the "circulate" privilege in order to
385 proceed. To make sure that access control is correct, the
386 C<$flagsrequired> parameter must be specified correctly.
388 If the GranularPermissions system preference is ON, the
389 value of each key in the C<flagsrequired> hash takes on an additional
394 The user must have access to all subfunctions of the module
395 specified by the hash key.
399 The user must have access to at least one subfunction of the module
400 specified by the hash key.
402 =item specific permission, e.g., 'export_catalog'
404 The user must have access to the specific subfunction list, which
405 must correspond to a row in the permissions table.
407 The C<$type> argument specifies whether the template should be
408 retrieved from the opac or intranet directory tree. "opac" is
409 assumed if it is not specified; however, if C<$type> is specified,
410 "intranet" is assumed if it is not "opac".
412 If C<$query> does not have a valid session ID associated with it
413 (i.e., the user has not logged in) or if the session has expired,
414 C<&checkauth> presents the user with a login page (from the point of
415 view of the original script, C<&checkauth> does not return). Once the
416 user has authenticated, C<&checkauth> restarts the original script
417 (this time, C<&checkauth> returns).
419 The login page is provided using a HTML::Template, which is set in the
420 systempreferences table or at the top of this file. The variable C<$type>
421 selects which template to use, either the opac or the intranet
422 authentification template.
424 C<&checkauth> returns a user ID, a cookie, and a session ID. The
425 cookie should be sent back to the browser; it verifies that the user
430 sub _version_check ($$) {
434 # If Version syspref is unavailable, it means Koha is beeing installed,
435 # and so we must redirect to OPAC maintenance page or to the WebInstaller
436 # also, if OpacMaintenance is ON, OPAC should redirect to maintenance
437 if (C4::Context->preference('OpacMaintenance') && $type eq 'opac') {
438 warn "OPAC Install required, redirecting to maintenance";
439 print $query->redirect("/cgi-bin/koha/maintenance.pl");
441 unless ($version = C4::Context->preference('Version')) { # assignment, not comparison
442 if ($type ne 'opac') {
443 warn "Install required, redirecting to Installer";
444 print $query->redirect("/cgi-bin/koha/installer/install.pl");
447 warn "OPAC Install required, redirecting to maintenance";
448 print $query->redirect("/cgi-bin/koha/maintenance.pl");
453 # check that database and koha version are the same
454 # there is no DB version, it's a fresh install,
455 # go to web installer
456 # there is a DB version, compare it to the code version
457 my $kohaversion=C4::Context::KOHAVERSION;
458 # remove the 3 last . to have a Perl number
459 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
460 $debug and print STDERR "kohaversion : $kohaversion\n";
461 if ($version < $kohaversion){
462 my $warning = "Database update needed, redirecting to %s. Database is $version and Koha is $kohaversion";
463 if ($type ne 'opac'){
464 warn sprintf($warning, 'Installer');
465 print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
467 warn sprintf("OPAC: " . $warning, 'maintenance');
468 print $query->redirect("/cgi-bin/koha/maintenance.pl");
476 open L, ">>/tmp/sessionlog" or warn "ERROR: Cannot append to /tmp/sessionlog";
477 printf L join("\n",@_);
483 $debug and warn "Checking Auth";
484 # $authnotrequired will be set for scripts which will run without authentication
485 my $authnotrequired = shift;
486 my $flagsrequired = shift;
488 $type = 'opac' unless $type;
490 my $dbh = C4::Context->dbh;
491 my $timeout = C4::Context->preference('timeout');
493 if ($timeout =~ /(\d+)[dD]/) {
494 $timeout = $1 * 86400;
496 $timeout = 600 unless $timeout;
498 _version_check($type,$query);
502 my ( $userid, $cookie, $sessionID, $flags, $barshelves, $pubshelves );
503 my $logout = $query->param('logout.x');
505 if ( $userid = $ENV{'REMOTE_USER'} ) {
506 # Using Basic Authentication, no cookies required
507 $cookie = $query->cookie(
508 -name => 'CGISESSID',
514 elsif ( $sessionID = $query->cookie("CGISESSID")) { # assignment, not comparison
515 my $session = get_session($sessionID);
516 C4::Context->_new_userenv($sessionID);
517 my ($ip, $lasttime, $sessiontype);
519 C4::Context::set_userenv(
520 $session->param('number'), $session->param('id'),
521 $session->param('cardnumber'), $session->param('firstname'),
522 $session->param('surname'), $session->param('branch'),
523 $session->param('branchname'), $session->param('flags'),
524 $session->param('emailaddress'), $session->param('branchprinter')
526 C4::Context::set_shelves_userenv('bar',$session->param('barshelves'));
527 C4::Context::set_shelves_userenv('pub',$session->param('pubshelves'));
528 C4::Context::set_shelves_userenv('tot',$session->param('totshelves'));
529 $debug and printf STDERR "AUTH_SESSION: (%s)\t%s %s - %s\n", map {$session->param($_)} qw(cardnumber firstname surname branch) ;
530 $ip = $session->param('ip');
531 $lasttime = $session->param('lasttime');
532 $userid = $session->param('id');
533 $sessiontype = $session->param('sessiontype');
536 if ( ($query->param('koha_login_context')) && ($query->param('userid') ne $session->param('id')) ) {
537 #if a user enters an id ne to the id in the current session, we need to log them in...
538 #first we need to clear the anonymous session...
539 $debug and warn "query id = " . $query->param('userid') . " but session id = " . $session->param('id');
542 C4::Context->_unset_userenv($sessionID);
547 # voluntary logout the user
550 C4::Context->_unset_userenv($sessionID);
551 _session_log(sprintf "%20s from %16s logged out at %30s (manually).\n", $userid,$ip,localtime);
555 elsif ( $lasttime < time() - $timeout ) {
557 $info{'timed_out'} = 1;
559 C4::Context->_unset_userenv($sessionID);
560 _session_log(sprintf "%20s from %16s logged out at %30s (inactivity).\n", $userid,$ip,localtime);
564 elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
565 # Different ip than originally logged in from
566 $info{'oldip'} = $ip;
567 $info{'newip'} = $ENV{'REMOTE_ADDR'};
568 $info{'different_ip'} = 1;
570 C4::Context->_unset_userenv($sessionID);
571 _session_log(sprintf "%20s from %16s logged out at %30s (ip changed to %16s).\n", $userid,$ip,localtime, $info{'newip'});
576 $cookie = $query->cookie( CGISESSID => $session->id );
577 $session->param('lasttime',time());
578 unless ( $sessiontype eq 'anon' ) { #if this is an anonymous session, we want to update the session, but not behave as if they are logged in...
579 $flags = haspermission( $dbh, $userid, $flagsrequired );
583 $info{'nopermission'} = 1;
588 unless ($userid || $sessionID) {
589 #we initiate a session prior to checking for a username to allow for anonymous sessions...
590 my $session = get_session("") or die "Auth ERROR: Cannot get_session()";
591 my $sessionID = $session->id;
592 C4::Context->_new_userenv($sessionID);
593 $cookie = $query->cookie(CGISESSID => $sessionID);
594 if ( $userid = $query->param('userid') ) {
595 my $password = $query->param('password');
596 my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
598 _session_log(sprintf "%20s from %16s logged in at %30s.\n", $userid,$ENV{'REMOTE_ADDR'},localtime);
599 if ( $flags = haspermission( $dbh, $userid, $flagsrequired ) ) {
603 $info{'nopermission'} = 1;
604 C4::Context->_unset_userenv($sessionID);
607 my ($borrowernumber, $firstname, $surname, $userflags,
608 $branchcode, $branchname, $branchprinter, $emailaddress);
610 if ( $return == 1 ) {
612 SELECT borrowernumber, firstname, surname, flags, borrowers.branchcode,
613 branches.branchname as branchname,
614 branches.branchprinter as branchprinter,
617 LEFT JOIN branches on borrowers.branchcode=branches.branchcode
619 my $sth = $dbh->prepare("$select where userid=?");
620 $sth->execute($userid);
621 unless ($sth->rows) {
622 $debug and print STDERR "AUTH_1: no rows for userid='$userid'\n";
623 $sth = $dbh->prepare("$select where cardnumber=?");
624 $sth->execute($cardnumber);
625 unless ($sth->rows) {
626 $debug and print STDERR "AUTH_2a: no rows for cardnumber='$cardnumber'\n";
627 $sth->execute($userid);
628 unless ($sth->rows) {
629 $debug and print STDERR "AUTH_2b: no rows for userid='$userid' AS cardnumber\n";
634 ($borrowernumber, $firstname, $surname, $userflags,
635 $branchcode, $branchname, $branchprinter, $emailaddress) = $sth->fetchrow;
636 $debug and print STDERR "AUTH_3 results: " .
637 "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress\n";
639 print STDERR "AUTH_3: no results for userid='$userid', cardnumber='$cardnumber'.\n";
642 # launch a sequence to check if we have a ip for the branch, i
643 # if we have one we replace the branchcode of the userenv by the branch bound in the ip.
645 my $ip = $ENV{'REMOTE_ADDR'};
646 # if they specify at login, use that
647 if ($query->param('branch')) {
648 $branchcode = $query->param('branch');
649 $branchname = GetBranchName($branchcode);
651 my $branches = GetBranches();
652 if (C4::Context->boolean_preference('IndependantBranches') && C4::Context->boolean_preference('Autolocation')){
653 # we have to check they are coming from the right ip range
654 my $domain = $branches->{$branchcode}->{'branchip'};
655 if ($ip !~ /^$domain/){
657 $info{'wrongip'} = 1;
662 foreach my $br ( keys %$branches ) {
663 # now we work with the treatment of ip
664 my $domain = $branches->{$br}->{'branchip'};
665 if ( $domain && $ip =~ /^$domain/ ) {
666 $branchcode = $branches->{$br}->{'branchcode'};
668 # new op dev : add the branchprinter and branchname in the cookie
669 $branchprinter = $branches->{$br}->{'branchprinter'};
670 $branchname = $branches->{$br}->{'branchname'};
673 $session->param('number',$borrowernumber);
674 $session->param('id',$userid);
675 $session->param('cardnumber',$cardnumber);
676 $session->param('firstname',$firstname);
677 $session->param('surname',$surname);
678 $session->param('branch',$branchcode);
679 $session->param('branchname',$branchname);
680 $session->param('flags',$userflags);
681 $session->param('emailaddress',$emailaddress);
682 $session->param('ip',$session->remote_addr());
683 $session->param('lasttime',time());
684 $debug and printf STDERR "AUTH_4: (%s)\t%s %s - %s\n", map {$session->param($_)} qw(cardnumber firstname surname branch) ;
686 elsif ( $return == 2 ) {
687 #We suppose the user is the superlibrarian
689 $session->param('number',0);
690 $session->param('id',C4::Context->config('user'));
691 $session->param('cardnumber',C4::Context->config('user'));
692 $session->param('firstname',C4::Context->config('user'));
693 $session->param('surname',C4::Context->config('user'));
694 $session->param('branch','NO_LIBRARY_SET');
695 $session->param('branchname','NO_LIBRARY_SET');
696 $session->param('flags',1);
697 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
698 $session->param('ip',$session->remote_addr());
699 $session->param('lasttime',time());
701 C4::Context::set_userenv(
702 $session->param('number'), $session->param('id'),
703 $session->param('cardnumber'), $session->param('firstname'),
704 $session->param('surname'), $session->param('branch'),
705 $session->param('branchname'), $session->param('flags'),
706 $session->param('emailaddress'), $session->param('branchprinter')
709 # Grab borrower's shelves and public shelves and add them to the session
710 # $row_count determines how many records are returned from the db query
711 # and the number of lists to be displayed of each type in the 'Lists' button drop down
712 my $row_count = 10; # FIXME:This probably should be a syspref
713 my ($total, $totshelves, $barshelves, $pubshelves);
714 ($barshelves, $totshelves) = C4::VirtualShelves::GetRecentShelves(1, $row_count, $borrowernumber);
715 $total->{'bartotal'} = $totshelves;
716 ($pubshelves, $totshelves) = C4::VirtualShelves::GetRecentShelves(2, $row_count, undef);
717 $total->{'pubtotal'} = $totshelves;
718 $session->param('barshelves', $barshelves->[0]);
719 $session->param('pubshelves', $pubshelves->[0]);
720 $session->param('totshelves', $total);
722 C4::Context::set_shelves_userenv('bar',$barshelves->[0]);
723 C4::Context::set_shelves_userenv('pub',$pubshelves->[0]);
724 C4::Context::set_shelves_userenv('tot',$total);
728 $info{'invalid_username_or_password'} = 1;
729 C4::Context->_unset_userenv($sessionID);
732 } # END if ( $userid = $query->param('userid') )
733 elsif ($type eq "opac") {
734 # if we are here this is an anonymous session; add public lists to it and a few other items...
735 # anonymous sessions are created only for the OPAC
736 $debug and warn "Initiating an anonymous session...";
738 # Grab the public shelves and add to the session...
739 my $row_count = 20; # FIXME:This probably should be a syspref
740 my ($total, $totshelves, $pubshelves);
741 ($pubshelves, $totshelves) = C4::VirtualShelves::GetRecentShelves(2, $row_count, undef);
742 $total->{'pubtotal'} = $totshelves;
743 $session->param('pubshelves', $pubshelves->[0]);
744 $session->param('totshelves', $total);
745 C4::Context::set_shelves_userenv('pub',$pubshelves->[0]);
746 C4::Context::set_shelves_userenv('tot',$total);
748 # setting a couple of other session vars...
749 $session->param('ip',$session->remote_addr());
750 $session->param('lasttime',time());
751 $session->param('sessiontype','anon');
753 } # END unless ($userid)
754 my $insecure = C4::Context->boolean_preference('insecure');
756 # finished authentification, now respond
757 if ( $loggedin || $authnotrequired || ( defined($insecure) && $insecure ) )
761 $cookie = $query->cookie( CGISESSID => '' );
763 return ( $userid, $cookie, $sessionID, $flags );
768 # AUTH rejected, show the login/password template, after checking the DB.
772 # get the inputs from the incoming query
774 foreach my $name ( param $query) {
775 (next) if ( $name eq 'userid' || $name eq 'password' );
776 my $value = $query->param($name);
777 push @inputs, { name => $name, value => $value };
779 # get the branchloop, which we need for authentication
780 my $branches = GetBranches();
782 for my $branch_hash (sort keys %$branches) {
783 push @branch_loop, {branchcode => "$branch_hash", branchname => $branches->{$branch_hash}->{'branchname'}, };
786 my $template_name = ( $type eq 'opac' ) ? 'opac-auth.tmpl' : 'auth.tmpl';
787 my $template = gettemplate( $template_name, $type, $query );
788 $template->param(branchloop => \@branch_loop,);
792 suggestion => C4::Context->preference("suggestion"),
793 virtualshelves => C4::Context->preference("virtualshelves"),
794 LibraryName => C4::Context->preference("LibraryName"),
795 opacuserlogin => C4::Context->preference("opacuserlogin"),
796 OpacNav => C4::Context->preference("OpacNav"),
797 opaccredits => C4::Context->preference("opaccredits"),
798 opacreadinghistory => C4::Context->preference("opacreadinghistory"),
799 opacsmallimage => C4::Context->preference("opacsmallimage"),
800 opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
801 opaccolorstylesheet => C4::Context->preference("opaccolorstylesheet"),
802 opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
803 opacuserjs => C4::Context->preference("opacuserjs"),
804 opacbookbag => "" . C4::Context->preference("opacbookbag"),
805 OpacCloud => C4::Context->preference("OpacCloud"),
806 OpacTopissue => C4::Context->preference("OpacTopissue"),
807 OpacAuthorities => C4::Context->preference("OpacAuthorities"),
808 OpacBrowser => C4::Context->preference("OpacBrowser"),
809 opacheader => C4::Context->preference("opacheader"),
810 TagsEnabled => C4::Context->preference("TagsEnabled"),
811 OPACUserCSS => C4::Context->preference("OPACUserCSS"),
812 intranetcolorstylesheet =>
813 C4::Context->preference("intranetcolorstylesheet"),
814 intranetstylesheet => C4::Context->preference("intranetstylesheet"),
815 IntranetNav => C4::Context->preference("IntranetNav"),
816 intranetuserjs => C4::Context->preference("intranetuserjs"),
817 TemplateEncoding => C4::Context->preference("TemplateEncoding"),
818 IndependantBranches=> C4::Context->preference("IndependantBranches"),
819 AutoLocation => C4::Context->preference("AutoLocation"),
820 wrongip => $info{'wrongip'}
823 $template->param( loginprompt => 1 ) unless $info{'nopermission'};
825 my $self_url = $query->url( -absolute => 1 );
828 LibraryName => C4::Context->preference("LibraryName"),
830 $template->param( \%info );
831 # $cookie = $query->cookie(CGISESSID => $session->id
833 print $query->header(
834 -type => 'text/html',
844 ($status, $cookie, $sessionId) = check_api_auth($query, $userflags);
846 Given a CGI query containing the parameters 'userid' and 'password' and/or a session
847 cookie, determine if the user has the privileges specified by C<$userflags>.
849 C<check_api_auth> is is meant for authenticating users of web services, and
850 consequently will always return and will not attempt to redirect the user
853 If a valid session cookie is already present, check_api_auth will return a status
854 of "ok", the cookie, and the Koha session ID.
856 If no session cookie is present, check_api_auth will check the 'userid' and 'password
857 parameters and create a session cookie and Koha session if the supplied credentials
860 Possible return values in C<$status> are:
864 =item "ok" -- user authenticated; C<$cookie> and C<$sessionid> have valid values.
866 =item "failed" -- credentials are not correct; C<$cookie> and C<$sessionid> are undef
868 =item "maintenance" -- DB is in maintenance mode; no login possible at the moment
870 =item "expired -- session cookie has expired; API user should resubmit userid and password
878 my $flagsrequired = shift;
880 my $dbh = C4::Context->dbh;
881 my $timeout = C4::Context->preference('timeout');
882 $timeout = 600 unless $timeout;
884 unless (C4::Context->preference('Version')) {
885 # database has not been installed yet
886 return ("maintenance", undef, undef);
888 my $kohaversion=C4::Context::KOHAVERSION;
889 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
890 if (C4::Context->preference('Version') < $kohaversion) {
891 # database in need of version update; assume that
892 # no API should be called while databsae is in
894 return ("maintenance", undef, undef);
897 # FIXME -- most of what follows is a copy-and-paste
898 # of code from checkauth. There is an obvious need
899 # for refactoring to separate the various parts of
900 # the authentication code, but as of 2007-11-19 this
901 # is deferred so as to not introduce bugs into the
902 # regular authentication code for Koha 3.0.
904 # see if we have a valid session cookie already
905 # however, if a userid parameter is present (i.e., from
906 # a form submission, assume that any current cookie
908 my $sessionID = undef;
909 unless ($query->param('userid')) {
910 $sessionID = $query->cookie("CGISESSID");
913 my $session = get_session($sessionID);
914 C4::Context->_new_userenv($sessionID);
916 C4::Context::set_userenv(
917 $session->param('number'), $session->param('id'),
918 $session->param('cardnumber'), $session->param('firstname'),
919 $session->param('surname'), $session->param('branch'),
920 $session->param('branchname'), $session->param('flags'),
921 $session->param('emailaddress'), $session->param('branchprinter')
924 my $ip = $session->param('ip');
925 my $lasttime = $session->param('lasttime');
926 my $userid = $session->param('id');
927 if ( $lasttime < time() - $timeout ) {
930 C4::Context->_unset_userenv($sessionID);
933 return ("expired", undef, undef);
934 } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
937 C4::Context->_unset_userenv($sessionID);
940 return ("expired", undef, undef);
942 my $cookie = $query->cookie( CGISESSID => $session->id );
943 $session->param('lasttime',time());
944 my $flags = haspermission( $dbh, $userid, $flagsrequired );
946 return ("ok", $cookie, $sessionID);
949 C4::Context->_unset_userenv($sessionID);
952 return ("failed", undef, undef);
956 return ("expired", undef, undef);
960 my $userid = $query->param('userid');
961 my $password = $query->param('password');
962 unless ($userid and $password) {
963 # caller did something wrong, fail the authenticateion
964 return ("failed", undef, undef);
966 my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
967 if ($return and haspermission( $dbh, $userid, $flagsrequired)) {
968 my $session = get_session("");
969 return ("failed", undef, undef) unless $session;
971 my $sessionID = $session->id;
972 C4::Context->_new_userenv($sessionID);
973 my $cookie = $query->cookie(CGISESSID => $sessionID);
974 if ( $return == 1 ) {
976 $borrowernumber, $firstname, $surname,
977 $userflags, $branchcode, $branchname,
978 $branchprinter, $emailaddress
982 "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=?"
984 $sth->execute($userid);
986 $borrowernumber, $firstname, $surname,
987 $userflags, $branchcode, $branchname,
988 $branchprinter, $emailaddress
989 ) = $sth->fetchrow if ( $sth->rows );
991 unless ($sth->rows ) {
992 my $sth = $dbh->prepare(
993 "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=?"
995 $sth->execute($cardnumber);
997 $borrowernumber, $firstname, $surname,
998 $userflags, $branchcode, $branchname,
999 $branchprinter, $emailaddress
1000 ) = $sth->fetchrow if ( $sth->rows );
1002 unless ( $sth->rows ) {
1003 $sth->execute($userid);
1005 $borrowernumber, $firstname, $surname, $userflags,
1006 $branchcode, $branchname, $branchprinter, $emailaddress
1007 ) = $sth->fetchrow if ( $sth->rows );
1011 my $ip = $ENV{'REMOTE_ADDR'};
1012 # if they specify at login, use that
1013 if ($query->param('branch')) {
1014 $branchcode = $query->param('branch');
1015 $branchname = GetBranchName($branchcode);
1017 my $branches = GetBranches();
1019 foreach my $br ( keys %$branches ) {
1020 # now we work with the treatment of ip
1021 my $domain = $branches->{$br}->{'branchip'};
1022 if ( $domain && $ip =~ /^$domain/ ) {
1023 $branchcode = $branches->{$br}->{'branchcode'};
1025 # new op dev : add the branchprinter and branchname in the cookie
1026 $branchprinter = $branches->{$br}->{'branchprinter'};
1027 $branchname = $branches->{$br}->{'branchname'};
1030 $session->param('number',$borrowernumber);
1031 $session->param('id',$userid);
1032 $session->param('cardnumber',$cardnumber);
1033 $session->param('firstname',$firstname);
1034 $session->param('surname',$surname);
1035 $session->param('branch',$branchcode);
1036 $session->param('branchname',$branchname);
1037 $session->param('flags',$userflags);
1038 $session->param('emailaddress',$emailaddress);
1039 $session->param('ip',$session->remote_addr());
1040 $session->param('lasttime',time());
1041 } elsif ( $return == 2 ) {
1042 #We suppose the user is the superlibrarian
1043 $session->param('number',0);
1044 $session->param('id',C4::Context->config('user'));
1045 $session->param('cardnumber',C4::Context->config('user'));
1046 $session->param('firstname',C4::Context->config('user'));
1047 $session->param('surname',C4::Context->config('user'));
1048 $session->param('branch','NO_LIBRARY_SET');
1049 $session->param('branchname','NO_LIBRARY_SET');
1050 $session->param('flags',1);
1051 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
1052 $session->param('ip',$session->remote_addr());
1053 $session->param('lasttime',time());
1055 C4::Context::set_userenv(
1056 $session->param('number'), $session->param('id'),
1057 $session->param('cardnumber'), $session->param('firstname'),
1058 $session->param('surname'), $session->param('branch'),
1059 $session->param('branchname'), $session->param('flags'),
1060 $session->param('emailaddress'), $session->param('branchprinter')
1062 return ("ok", $cookie, $sessionID);
1064 return ("failed", undef, undef);
1069 =item check_cookie_auth
1071 ($status, $sessionId) = check_api_auth($cookie, $userflags);
1073 Given a CGISESSID cookie set during a previous login to Koha, determine
1074 if the user has the privileges specified by C<$userflags>.
1076 C<check_cookie_auth> is meant for authenticating special services
1077 such as tools/upload-file.pl that are invoked by other pages that
1078 have been authenticated in the usual way.
1080 Possible return values in C<$status> are:
1084 =item "ok" -- user authenticated; C<$sessionID> have valid values.
1086 =item "failed" -- credentials are not correct; C<$sessionid> are undef
1088 =item "maintenance" -- DB is in maintenance mode; no login possible at the moment
1090 =item "expired -- session cookie has expired; API user should resubmit userid and password
1096 sub check_cookie_auth {
1098 my $flagsrequired = shift;
1100 my $dbh = C4::Context->dbh;
1101 my $timeout = C4::Context->preference('timeout');
1102 $timeout = 600 unless $timeout;
1104 unless (C4::Context->preference('Version')) {
1105 # database has not been installed yet
1106 return ("maintenance", undef);
1108 my $kohaversion=C4::Context::KOHAVERSION;
1109 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
1110 if (C4::Context->preference('Version') < $kohaversion) {
1111 # database in need of version update; assume that
1112 # no API should be called while databsae is in
1114 return ("maintenance", undef);
1117 # FIXME -- most of what follows is a copy-and-paste
1118 # of code from checkauth. There is an obvious need
1119 # for refactoring to separate the various parts of
1120 # the authentication code, but as of 2007-11-23 this
1121 # is deferred so as to not introduce bugs into the
1122 # regular authentication code for Koha 3.0.
1124 # see if we have a valid session cookie already
1125 # however, if a userid parameter is present (i.e., from
1126 # a form submission, assume that any current cookie
1128 unless (defined $cookie and $cookie) {
1129 return ("failed", undef);
1131 my $sessionID = $cookie;
1132 my $session = get_session($sessionID);
1133 C4::Context->_new_userenv($sessionID);
1135 C4::Context::set_userenv(
1136 $session->param('number'), $session->param('id'),
1137 $session->param('cardnumber'), $session->param('firstname'),
1138 $session->param('surname'), $session->param('branch'),
1139 $session->param('branchname'), $session->param('flags'),
1140 $session->param('emailaddress'), $session->param('branchprinter')
1143 my $ip = $session->param('ip');
1144 my $lasttime = $session->param('lasttime');
1145 my $userid = $session->param('id');
1146 if ( $lasttime < time() - $timeout ) {
1149 C4::Context->_unset_userenv($sessionID);
1152 return ("expired", undef);
1153 } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
1154 # IP address changed
1156 C4::Context->_unset_userenv($sessionID);
1159 return ("expired", undef);
1161 $session->param('lasttime',time());
1162 my $flags = haspermission( $dbh, $userid, $flagsrequired );
1164 return ("ok", $sessionID);
1167 C4::Context->_unset_userenv($sessionID);
1170 return ("failed", undef);
1174 return ("expired", undef);
1181 my $session = get_session($sessionID);
1183 Given a session ID, retrieve the CGI::Session object used to store
1184 the session's state. The session object can be used to store
1185 data that needs to be accessed by different scripts during a
1188 If the C<$sessionID> parameter is an empty string, a new session
1194 my $sessionID = shift;
1195 my $storage_method = C4::Context->preference('SessionStorage');
1196 my $dbh = C4::Context->dbh;
1198 if ($storage_method eq 'mysql'){
1199 $session = new CGI::Session("driver:MySQL;serializer:yaml;id:md5", $sessionID, {Handle=>$dbh});
1201 elsif ($storage_method eq 'Pg') {
1202 $session = new CGI::Session("driver:PostgreSQL;serializer:yaml;id:md5", $sessionID, {Handle=>$dbh});
1205 # catch all defaults to tmp should work on all systems
1206 $session = new CGI::Session("driver:File;serializer:yaml;id:md5", $sessionID, {Directory=>'/tmp'});
1213 my ( $dbh, $userid, $password ) = @_;
1215 $debug and print "## checkpw - checking LDAP\n";
1216 my ($retval,$retcard) = checkpw_ldap(@_); # EXTERNAL AUTH
1217 ($retval) and return ($retval,$retcard);
1223 "select password,cardnumber,borrowernumber,userid,firstname,surname,branchcode,flags from borrowers where userid=?"
1225 $sth->execute($userid);
1227 my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
1228 $surname, $branchcode, $flags )
1230 if ( md5_base64($password) eq $md5password ) {
1232 C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
1233 $firstname, $surname, $branchcode, $flags );
1234 return 1, $cardnumber;
1239 "select password,cardnumber,borrowernumber,userid, firstname,surname,branchcode,flags from borrowers where cardnumber=?"
1241 $sth->execute($userid);
1243 my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
1244 $surname, $branchcode, $flags )
1246 if ( md5_base64($password) eq $md5password ) {
1248 C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
1249 $firstname, $surname, $branchcode, $flags );
1253 if ( $userid && $userid eq C4::Context->config('user')
1254 && "$password" eq C4::Context->config('pass') )
1257 # Koha superuser account
1258 # C4::Context->set_userenv(0,0,C4::Context->config('user'),C4::Context->config('user'),C4::Context->config('user'),"",1);
1261 if ( $userid && $userid eq 'demo'
1262 && "$password" eq 'demo'
1263 && C4::Context->config('demo') )
1266 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
1267 # some features won't be effective : modify systempref, modify MARC structure,
1275 $authflags = getuserflags($flags,$dbh);
1276 Translates integer flags into permissions strings hash.
1278 C<$flags> is the integer userflags value ( borrowers.userflags )
1279 C<$authflags> is a hashref of permissions
1288 $flags = 0 unless $flags;
1289 my $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
1292 while ( my ( $bit, $flag, $defaulton ) = $sth->fetchrow ) {
1293 if ( ( $flags & ( 2**$bit ) ) || $defaulton ) {
1294 $userflags->{$flag} = 1;
1297 $userflags->{$flag} = 0;
1301 # get subpermissions and merge with top-level permissions
1302 my $user_subperms = get_user_subpermissions($userid);
1303 foreach my $module (keys %$user_subperms) {
1304 next if $userflags->{$module} == 1; # user already has permission for everything in this module
1305 $userflags->{$module} = $user_subperms->{$module};
1311 =item get_user_subpermissions
1315 my $user_perm_hashref = get_user_subpermissions($userid);
1319 Given the userid (note, not the borrowernumber) of a staff user,
1320 return a hashref of hashrefs of the specific subpermissions
1321 accorded to the user. An example return is
1325 export_catalog => 1,
1326 import_patrons => 1,
1330 The top-level hash-key is a module or function code from
1331 userflags.flag, while the second-level key is a code
1334 The results of this function do not give a complete picture
1335 of the functions that a staff user can access; it is also
1336 necessary to check borrowers.flags.
1340 sub get_user_subpermissions {
1343 my $dbh = C4::Context->dbh;
1344 my $sth = $dbh->prepare("SELECT flag, code
1345 FROM user_permissions
1346 JOIN permissions USING (module_bit, code)
1347 JOIN userflags ON (module_bit = bit)
1348 JOIN borrowers USING (borrowernumber)
1350 $sth->execute($userid);
1352 my $user_perms = {};
1353 while (my $perm = $sth->fetchrow_hashref) {
1354 $user_perms->{$perm->{'flag'}}->{$perm->{'code'}} = 1;
1359 =item get_all_subpermissions
1363 my $perm_hashref = get_all_subpermissions();
1367 Returns a hashref of hashrefs defining all specific
1368 permissions currently defined. The return value
1369 has the same structure as that of C<get_user_subpermissions>,
1370 except that the innermost hash value is the description
1371 of the subpermission.
1375 sub get_all_subpermissions {
1376 my $dbh = C4::Context->dbh;
1377 my $sth = $dbh->prepare("SELECT flag, code, description
1379 JOIN userflags ON (module_bit = bit)");
1383 while (my $perm = $sth->fetchrow_hashref) {
1384 $all_perms->{$perm->{'flag'}}->{$perm->{'code'}} = $perm->{'description'};
1391 $flags = ($dbh,$member,$flagsrequired);
1393 C<$member> may be either userid or overloaded with $borrower hashref from GetMemberDetails.
1394 C<$flags> is a hashref of required flags like C<$borrower-<{authflags}>
1396 Returns member's flags or 0 if a permission is not met.
1401 my ( $dbh, $userid, $flagsrequired ) = @_;
1402 my ($flags,$intflags);
1403 $dbh=C4::Context->dbh unless($dbh);
1405 $intflags = $userid->{'flags'};
1407 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE userid=?");
1408 $sth->execute($userid);
1409 my ($intflags) = $sth->fetchrow;
1410 $flags = getuserflags( $intflags, $userid, $dbh );
1412 if ( $userid eq C4::Context->config('user') ) {
1413 # Super User Account from /etc/koha.conf
1414 $flags->{'superlibrarian'} = 1;
1416 if ( $userid eq 'demo' && C4::Context->config('demo') ) {
1417 # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
1418 $flags->{'superlibrarian'} = 1;
1420 return $flags if $flags->{superlibrarian};
1421 foreach my $module ( keys %$flagsrequired ) {
1422 if (C4::Context->preference('GranularPermissions')) {
1423 my $subperm = $flagsrequired->{$module};
1424 if ($subperm eq '*') {
1425 return 0 unless ( $flags->{$module} == 1 or ref($flags->{$module}) );
1427 return 0 unless ( $flags->{$module} == 1 or
1428 ( ref($flags->{$module}) and
1429 exists $flags->{$module}->{$subperm} and
1430 $flags->{$module}->{$subperm} == 1
1435 return 0 unless ( $flags->{$module} );
1439 #FIXME - This fcn should return the failed permission so a suitable error msg can be delivered.
1443 sub getborrowernumber {
1445 my $dbh = C4::Context->dbh;
1446 for my $field ( 'userid', 'cardnumber' ) {
1448 $dbh->prepare("select borrowernumber from borrowers where $field=?");
1449 $sth->execute($userid);
1451 my ($bnumber) = $sth->fetchrow;
1458 END { } # module clean-up code here (global destructor)