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"),
272 SyndeticsClientCode => C4::Context->preference("SyndeticsClientCode"),
273 SyndeticsEnabled => C4::Context->preference("SyndeticsEnabled"),
274 SyndeticsCoverImages => C4::Context->preference("SyndeticsCoverImages"),
275 SyndeticsTOC => C4::Context->preference("SyndeticsTOC"),
276 SyndeticsSummary => C4::Context->preference("SyndeticsSummary"),
277 SyndeticsEditions => C4::Context->preference("SyndeticsEditions"),
278 SyndeticsExcerpt => C4::Context->preference("SyndeticsExcerpt"),
279 SyndeticsReviews => C4::Context->preference("SyndeticsReviews"),
280 SyndeticsAuthorNotes => C4::Context->preference("SyndeticsAuthorNotes"),
281 SyndeticsAwards => C4::Context->preference("SyndeticsAwards"),
282 SyndeticsSeries => C4::Context->preference("SyndeticsSeries"),
285 if ( $in->{'type'} eq "intranet" ) {
287 AmazonContent => C4::Context->preference("AmazonContent"),
288 AmazonSimilarItems => C4::Context->preference("AmazonSimilarItems"),
289 AutoLocation => C4::Context->preference("AutoLocation"),
290 "BiblioDefaultView".C4::Context->preference("IntranetBiblioDefaultView") => 1,
291 CircAutocompl => C4::Context->preference("CircAutocompl"),
292 FRBRizeEditions => C4::Context->preference("FRBRizeEditions"),
293 IndependantBranches => C4::Context->preference("IndependantBranches"),
294 IntranetNav => C4::Context->preference("IntranetNav"),
295 IntranetmainUserblock => C4::Context->preference("IntranetmainUserblock"),
296 LibraryName => C4::Context->preference("LibraryName"),
297 LoginBranchname => (C4::Context->userenv?C4::Context->userenv->{"branchname"}:"insecure"),
298 TemplateEncoding => C4::Context->preference("TemplateEncoding"),
299 advancedMARCEditor => C4::Context->preference("advancedMARCEditor"),
300 canreservefromotherbranches => C4::Context->preference('canreservefromotherbranches'),
301 intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
302 intranetreadinghistory => C4::Context->preference("intranetreadinghistory"),
303 intranetstylesheet => C4::Context->preference("intranetstylesheet"),
304 intranetuserjs => C4::Context->preference("intranetuserjs"),
305 noItemTypeImages => C4::Context->preference("noItemTypeImages"),
306 suggestion => C4::Context->preference("suggestion"),
307 virtualshelves => C4::Context->preference("virtualshelves"),
311 warn "template type should be OPAC, here it is=[" . $in->{'type'} . "]" unless ( $in->{'type'} eq 'opac' );
312 my $LibraryNameTitle = C4::Context->preference("LibraryName");
313 $LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi;
314 $LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg;
316 AmazonContent => "" . C4::Context->preference("AmazonContent"),
317 AnonSuggestions => "" . C4::Context->preference("AnonSuggestions"),
318 AuthorisedValueImages => C4::Context->preference("AuthorisedValueImages"),
319 LibraryName => "" . C4::Context->preference("LibraryName"),
320 LibraryNameTitle => "" . $LibraryNameTitle,
321 LoginBranchname => C4::Context->userenv?C4::Context->userenv->{"branchname"}:"",
322 OPACAmazonSimilarItems => "" . C4::Context->preference("OPACAmazonSimilarItems"),
323 OPACFRBRizeEditions => C4::Context->preference("OPACFRBRizeEditions"),
324 OPACItemHolds => C4::Context->preference("OPACItemHolds"),
325 OPACShelfBrowser => "". C4::Context->preference("OPACShelfBrowser"),
326 OPACURLOpenInNewWindow => "" . C4::Context->preference("OPACURLOpenInNewWindow"),
327 OPACUserCSS => "". C4::Context->preference("OPACUserCSS"),
328 OPACViewOthersSuggestions => "" . C4::Context->preference("OPACViewOthersSuggestions"),
329 OpacAuthorities => C4::Context->preference("OpacAuthorities"),
330 OPACBaseURL => ($in->{'query'}->https() ? "https://" : "http://") .
331 $ENV{'SERVER_NAME'} .
332 ($ENV{'SERVER_PORT'} eq ($in->{'query'}->https() ? "443" : "80") ? '' : ":$ENV{'SERVER_PORT'}"),
333 OpacBrowser => C4::Context->preference("OpacBrowser"),
334 OpacCloud => C4::Context->preference("OpacCloud"),
335 OpacMainUserBlock => "" . C4::Context->preference("OpacMainUserBlock"),
336 OpacNav => "" . C4::Context->preference("OpacNav"),
337 OpacPasswordChange => C4::Context->preference("OpacPasswordChange"),
338 OpacTopissue => C4::Context->preference("OpacTopissue"),
339 RequestOnOpac => C4::Context->preference("RequestOnOpac"),
340 TemplateEncoding => "". C4::Context->preference("TemplateEncoding"),
341 'Version' => C4::Context->preference('Version'),
342 XSLTDetailsDisplay => C4::Context->preference("XSLTDetailsDisplay"),
343 XSLTResultsDisplay => C4::Context->preference("XSLTResultsDisplay"),
344 hidelostitems => C4::Context->preference("hidelostitems"),
345 mylibraryfirst => C4::Context->preference("SearchMyLibraryFirst"),
346 opacbookbag => "" . C4::Context->preference("opacbookbag"),
347 opaccolorstylesheet => "". C4::Context->preference("opaccolorstylesheet"),
348 opaccredits => "" . C4::Context->preference("opaccredits"),
349 opacheader => "" . C4::Context->preference("opacheader"),
350 opaclanguagesdisplay => "". C4::Context->preference("opaclanguagesdisplay"),
351 opaclayoutstylesheet => "". C4::Context->preference("opaclayoutstylesheet"),
352 opacreadinghistory => C4::Context->preference("opacreadinghistory"),
353 opacsmallimage => "" . C4::Context->preference("opacsmallimage"),
354 opacuserjs => C4::Context->preference("opacuserjs"),
355 opacuserlogin => "" . C4::Context->preference("opacuserlogin"),
356 reviewson => C4::Context->preference("reviewson"),
357 suggestion => "" . C4::Context->preference("suggestion"),
358 virtualshelves => "" . C4::Context->preference("virtualshelves"),
361 return ( $template, $borrowernumber, $cookie, $flags);
366 ($userid, $cookie, $sessionID) = &checkauth($query, $noauth, $flagsrequired, $type);
368 Verifies that the user is authorized to run this script. If
369 the user is authorized, a (userid, cookie, session-id, flags)
370 quadruple is returned. If the user is not authorized due to
371 insufficent privileges (see $flagsrequired below), it
372 displays an error page and exits. Otherwise, it displays the
373 login page and exits.
375 Note that C<&checkauth> will return if and only if the user
376 is authorized, so it should be called early on, before any
377 unfinished operations (e.g., if you've opened a file, then
378 C<&checkauth> won't close it for you).
380 C<$query> is the CGI object for the script calling C<&checkauth>.
382 The C<$noauth> argument is optional. If it is set, then no
383 authorization is required for the script.
385 C<&checkauth> fetches user and session information from C<$query> and
386 ensures that the user is authorized to run scripts that require
389 The C<$flagsrequired> argument specifies the required privileges
390 the user must have if the username and password are correct.
391 It should be specified as a reference-to-hash; keys in the hash
392 should be the "flags" for the user, as specified in the Members
393 intranet module. Any key specified must correspond to a "flag"
394 in the userflags table. E.g., { circulate => 1 } would specify
395 that the user must have the "circulate" privilege in order to
396 proceed. To make sure that access control is correct, the
397 C<$flagsrequired> parameter must be specified correctly.
399 If the GranularPermissions system preference is ON, the
400 value of each key in the C<flagsrequired> hash takes on an additional
405 The user must have access to all subfunctions of the module
406 specified by the hash key.
410 The user must have access to at least one subfunction of the module
411 specified by the hash key.
413 =item specific permission, e.g., 'export_catalog'
415 The user must have access to the specific subfunction list, which
416 must correspond to a row in the permissions table.
418 The C<$type> argument specifies whether the template should be
419 retrieved from the opac or intranet directory tree. "opac" is
420 assumed if it is not specified; however, if C<$type> is specified,
421 "intranet" is assumed if it is not "opac".
423 If C<$query> does not have a valid session ID associated with it
424 (i.e., the user has not logged in) or if the session has expired,
425 C<&checkauth> presents the user with a login page (from the point of
426 view of the original script, C<&checkauth> does not return). Once the
427 user has authenticated, C<&checkauth> restarts the original script
428 (this time, C<&checkauth> returns).
430 The login page is provided using a HTML::Template, which is set in the
431 systempreferences table or at the top of this file. The variable C<$type>
432 selects which template to use, either the opac or the intranet
433 authentification template.
435 C<&checkauth> returns a user ID, a cookie, and a session ID. The
436 cookie should be sent back to the browser; it verifies that the user
441 sub _version_check ($$) {
445 # If Version syspref is unavailable, it means Koha is beeing installed,
446 # and so we must redirect to OPAC maintenance page or to the WebInstaller
447 # also, if OpacMaintenance is ON, OPAC should redirect to maintenance
448 if (C4::Context->preference('OpacMaintenance') && $type eq 'opac') {
449 warn "OPAC Install required, redirecting to maintenance";
450 print $query->redirect("/cgi-bin/koha/maintenance.pl");
452 unless ($version = C4::Context->preference('Version')) { # assignment, not comparison
453 if ($type ne 'opac') {
454 warn "Install required, redirecting to Installer";
455 print $query->redirect("/cgi-bin/koha/installer/install.pl");
458 warn "OPAC Install required, redirecting to maintenance";
459 print $query->redirect("/cgi-bin/koha/maintenance.pl");
464 # check that database and koha version are the same
465 # there is no DB version, it's a fresh install,
466 # go to web installer
467 # there is a DB version, compare it to the code version
468 my $kohaversion=C4::Context::KOHAVERSION;
469 # remove the 3 last . to have a Perl number
470 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
471 $debug and print STDERR "kohaversion : $kohaversion\n";
472 if ($version < $kohaversion){
473 my $warning = "Database update needed, redirecting to %s. Database is $version and Koha is $kohaversion";
474 if ($type ne 'opac'){
475 warn sprintf($warning, 'Installer');
476 print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
478 warn sprintf("OPAC: " . $warning, 'maintenance');
479 print $query->redirect("/cgi-bin/koha/maintenance.pl");
487 open L, ">>/tmp/sessionlog" or warn "ERROR: Cannot append to /tmp/sessionlog";
488 printf L join("\n",@_);
494 $debug and warn "Checking Auth";
495 # $authnotrequired will be set for scripts which will run without authentication
496 my $authnotrequired = shift;
497 my $flagsrequired = shift;
499 $type = 'opac' unless $type;
501 my $dbh = C4::Context->dbh;
502 my $timeout = C4::Context->preference('timeout');
504 if ($timeout =~ /(\d+)[dD]/) {
505 $timeout = $1 * 86400;
507 $timeout = 600 unless $timeout;
509 _version_check($type,$query);
513 my ( $userid, $cookie, $sessionID, $flags, $barshelves, $pubshelves );
514 my $logout = $query->param('logout.x');
516 if ( $userid = $ENV{'REMOTE_USER'} ) {
517 # Using Basic Authentication, no cookies required
518 $cookie = $query->cookie(
519 -name => 'CGISESSID',
525 elsif ( $sessionID = $query->cookie("CGISESSID")) { # assignment, not comparison
526 my $session = get_session($sessionID);
527 C4::Context->_new_userenv($sessionID);
528 my ($ip, $lasttime, $sessiontype);
530 C4::Context::set_userenv(
531 $session->param('number'), $session->param('id'),
532 $session->param('cardnumber'), $session->param('firstname'),
533 $session->param('surname'), $session->param('branch'),
534 $session->param('branchname'), $session->param('flags'),
535 $session->param('emailaddress'), $session->param('branchprinter')
537 C4::Context::set_shelves_userenv('bar',$session->param('barshelves'));
538 C4::Context::set_shelves_userenv('pub',$session->param('pubshelves'));
539 C4::Context::set_shelves_userenv('tot',$session->param('totshelves'));
540 $debug and printf STDERR "AUTH_SESSION: (%s)\t%s %s - %s\n", map {$session->param($_)} qw(cardnumber firstname surname branch) ;
541 $ip = $session->param('ip');
542 $lasttime = $session->param('lasttime');
543 $userid = $session->param('id');
544 $sessiontype = $session->param('sessiontype');
547 if ( ($query->param('koha_login_context')) && ($query->param('userid') ne $session->param('id')) ) {
548 #if a user enters an id ne to the id in the current session, we need to log them in...
549 #first we need to clear the anonymous session...
550 $debug and warn "query id = " . $query->param('userid') . " but session id = " . $session->param('id');
553 C4::Context->_unset_userenv($sessionID);
558 # voluntary logout the user
561 C4::Context->_unset_userenv($sessionID);
562 _session_log(sprintf "%20s from %16s logged out at %30s (manually).\n", $userid,$ip,localtime);
566 elsif ( $lasttime < time() - $timeout ) {
568 $info{'timed_out'} = 1;
570 C4::Context->_unset_userenv($sessionID);
571 _session_log(sprintf "%20s from %16s logged out at %30s (inactivity).\n", $userid,$ip,localtime);
575 elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
576 # Different ip than originally logged in from
577 $info{'oldip'} = $ip;
578 $info{'newip'} = $ENV{'REMOTE_ADDR'};
579 $info{'different_ip'} = 1;
581 C4::Context->_unset_userenv($sessionID);
582 _session_log(sprintf "%20s from %16s logged out at %30s (ip changed to %16s).\n", $userid,$ip,localtime, $info{'newip'});
587 $cookie = $query->cookie( CGISESSID => $session->id );
588 $session->param('lasttime',time());
589 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...
590 $flags = haspermission( $dbh, $userid, $flagsrequired );
594 $info{'nopermission'} = 1;
599 unless ($userid || $sessionID) {
600 #we initiate a session prior to checking for a username to allow for anonymous sessions...
601 my $session = get_session("") or die "Auth ERROR: Cannot get_session()";
602 my $sessionID = $session->id;
603 C4::Context->_new_userenv($sessionID);
604 $cookie = $query->cookie(CGISESSID => $sessionID);
605 if ( $userid = $query->param('userid') ) {
606 my $password = $query->param('password');
607 my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
609 _session_log(sprintf "%20s from %16s logged in at %30s.\n", $userid,$ENV{'REMOTE_ADDR'},localtime);
610 if ( $flags = haspermission( $dbh, $userid, $flagsrequired ) ) {
614 $info{'nopermission'} = 1;
615 C4::Context->_unset_userenv($sessionID);
618 my ($borrowernumber, $firstname, $surname, $userflags,
619 $branchcode, $branchname, $branchprinter, $emailaddress);
621 if ( $return == 1 ) {
623 SELECT borrowernumber, firstname, surname, flags, borrowers.branchcode,
624 branches.branchname as branchname,
625 branches.branchprinter as branchprinter,
628 LEFT JOIN branches on borrowers.branchcode=branches.branchcode
630 my $sth = $dbh->prepare("$select where userid=?");
631 $sth->execute($userid);
632 unless ($sth->rows) {
633 $debug and print STDERR "AUTH_1: no rows for userid='$userid'\n";
634 $sth = $dbh->prepare("$select where cardnumber=?");
635 $sth->execute($cardnumber);
636 unless ($sth->rows) {
637 $debug and print STDERR "AUTH_2a: no rows for cardnumber='$cardnumber'\n";
638 $sth->execute($userid);
639 unless ($sth->rows) {
640 $debug and print STDERR "AUTH_2b: no rows for userid='$userid' AS cardnumber\n";
645 ($borrowernumber, $firstname, $surname, $userflags,
646 $branchcode, $branchname, $branchprinter, $emailaddress) = $sth->fetchrow;
647 $debug and print STDERR "AUTH_3 results: " .
648 "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress\n";
650 print STDERR "AUTH_3: no results for userid='$userid', cardnumber='$cardnumber'.\n";
653 # launch a sequence to check if we have a ip for the branch, i
654 # if we have one we replace the branchcode of the userenv by the branch bound in the ip.
656 my $ip = $ENV{'REMOTE_ADDR'};
657 # if they specify at login, use that
658 if ($query->param('branch')) {
659 $branchcode = $query->param('branch');
660 $branchname = GetBranchName($branchcode);
662 my $branches = GetBranches();
663 if (C4::Context->boolean_preference('IndependantBranches') && C4::Context->boolean_preference('Autolocation')){
664 # we have to check they are coming from the right ip range
665 my $domain = $branches->{$branchcode}->{'branchip'};
666 if ($ip !~ /^$domain/){
668 $info{'wrongip'} = 1;
673 foreach my $br ( keys %$branches ) {
674 # now we work with the treatment of ip
675 my $domain = $branches->{$br}->{'branchip'};
676 if ( $domain && $ip =~ /^$domain/ ) {
677 $branchcode = $branches->{$br}->{'branchcode'};
679 # new op dev : add the branchprinter and branchname in the cookie
680 $branchprinter = $branches->{$br}->{'branchprinter'};
681 $branchname = $branches->{$br}->{'branchname'};
684 $session->param('number',$borrowernumber);
685 $session->param('id',$userid);
686 $session->param('cardnumber',$cardnumber);
687 $session->param('firstname',$firstname);
688 $session->param('surname',$surname);
689 $session->param('branch',$branchcode);
690 $session->param('branchname',$branchname);
691 $session->param('flags',$userflags);
692 $session->param('emailaddress',$emailaddress);
693 $session->param('ip',$session->remote_addr());
694 $session->param('lasttime',time());
695 $debug and printf STDERR "AUTH_4: (%s)\t%s %s - %s\n", map {$session->param($_)} qw(cardnumber firstname surname branch) ;
697 elsif ( $return == 2 ) {
698 #We suppose the user is the superlibrarian
700 $session->param('number',0);
701 $session->param('id',C4::Context->config('user'));
702 $session->param('cardnumber',C4::Context->config('user'));
703 $session->param('firstname',C4::Context->config('user'));
704 $session->param('surname',C4::Context->config('user'));
705 $session->param('branch','NO_LIBRARY_SET');
706 $session->param('branchname','NO_LIBRARY_SET');
707 $session->param('flags',1);
708 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
709 $session->param('ip',$session->remote_addr());
710 $session->param('lasttime',time());
712 C4::Context::set_userenv(
713 $session->param('number'), $session->param('id'),
714 $session->param('cardnumber'), $session->param('firstname'),
715 $session->param('surname'), $session->param('branch'),
716 $session->param('branchname'), $session->param('flags'),
717 $session->param('emailaddress'), $session->param('branchprinter')
720 # Grab borrower's shelves and public shelves and add them to the session
721 # $row_count determines how many records are returned from the db query
722 # and the number of lists to be displayed of each type in the 'Lists' button drop down
723 my $row_count = 10; # FIXME:This probably should be a syspref
724 my ($total, $totshelves, $barshelves, $pubshelves);
725 ($barshelves, $totshelves) = C4::VirtualShelves::GetRecentShelves(1, $row_count, $borrowernumber);
726 $total->{'bartotal'} = $totshelves;
727 ($pubshelves, $totshelves) = C4::VirtualShelves::GetRecentShelves(2, $row_count, undef);
728 $total->{'pubtotal'} = $totshelves;
729 $session->param('barshelves', $barshelves->[0]);
730 $session->param('pubshelves', $pubshelves->[0]);
731 $session->param('totshelves', $total);
733 C4::Context::set_shelves_userenv('bar',$barshelves->[0]);
734 C4::Context::set_shelves_userenv('pub',$pubshelves->[0]);
735 C4::Context::set_shelves_userenv('tot',$total);
739 $info{'invalid_username_or_password'} = 1;
740 C4::Context->_unset_userenv($sessionID);
743 } # END if ( $userid = $query->param('userid') )
744 elsif ($type eq "opac") {
745 # if we are here this is an anonymous session; add public lists to it and a few other items...
746 # anonymous sessions are created only for the OPAC
747 $debug and warn "Initiating an anonymous session...";
749 # Grab the public shelves and add to the session...
750 my $row_count = 20; # FIXME:This probably should be a syspref
751 my ($total, $totshelves, $pubshelves);
752 ($pubshelves, $totshelves) = C4::VirtualShelves::GetRecentShelves(2, $row_count, undef);
753 $total->{'pubtotal'} = $totshelves;
754 $session->param('pubshelves', $pubshelves->[0]);
755 $session->param('totshelves', $total);
756 C4::Context::set_shelves_userenv('pub',$pubshelves->[0]);
757 C4::Context::set_shelves_userenv('tot',$total);
759 # setting a couple of other session vars...
760 $session->param('ip',$session->remote_addr());
761 $session->param('lasttime',time());
762 $session->param('sessiontype','anon');
764 } # END unless ($userid)
765 my $insecure = C4::Context->boolean_preference('insecure');
767 # finished authentification, now respond
768 if ( $loggedin || $authnotrequired || ( defined($insecure) && $insecure ) )
772 $cookie = $query->cookie( CGISESSID => '' );
774 return ( $userid, $cookie, $sessionID, $flags );
779 # AUTH rejected, show the login/password template, after checking the DB.
783 # get the inputs from the incoming query
785 foreach my $name ( param $query) {
786 (next) if ( $name eq 'userid' || $name eq 'password' );
787 my $value = $query->param($name);
788 push @inputs, { name => $name, value => $value };
790 # get the branchloop, which we need for authentication
791 my $branches = GetBranches();
793 for my $branch_hash (sort keys %$branches) {
794 push @branch_loop, {branchcode => "$branch_hash", branchname => $branches->{$branch_hash}->{'branchname'}, };
797 my $template_name = ( $type eq 'opac' ) ? 'opac-auth.tmpl' : 'auth.tmpl';
798 my $template = gettemplate( $template_name, $type, $query );
799 $template->param(branchloop => \@branch_loop,);
803 suggestion => C4::Context->preference("suggestion"),
804 virtualshelves => C4::Context->preference("virtualshelves"),
805 LibraryName => C4::Context->preference("LibraryName"),
806 opacuserlogin => C4::Context->preference("opacuserlogin"),
807 OpacNav => C4::Context->preference("OpacNav"),
808 opaccredits => C4::Context->preference("opaccredits"),
809 opacreadinghistory => C4::Context->preference("opacreadinghistory"),
810 opacsmallimage => C4::Context->preference("opacsmallimage"),
811 opaclayoutstylesheet => C4::Context->preference("opaclayoutstylesheet"),
812 opaccolorstylesheet => C4::Context->preference("opaccolorstylesheet"),
813 opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
814 opacuserjs => C4::Context->preference("opacuserjs"),
815 opacbookbag => "" . C4::Context->preference("opacbookbag"),
816 OpacCloud => C4::Context->preference("OpacCloud"),
817 OpacTopissue => C4::Context->preference("OpacTopissue"),
818 OpacAuthorities => C4::Context->preference("OpacAuthorities"),
819 OpacBrowser => C4::Context->preference("OpacBrowser"),
820 opacheader => C4::Context->preference("opacheader"),
821 TagsEnabled => C4::Context->preference("TagsEnabled"),
822 OPACUserCSS => C4::Context->preference("OPACUserCSS"),
823 intranetcolorstylesheet =>
824 C4::Context->preference("intranetcolorstylesheet"),
825 intranetstylesheet => C4::Context->preference("intranetstylesheet"),
826 IntranetNav => C4::Context->preference("IntranetNav"),
827 intranetuserjs => C4::Context->preference("intranetuserjs"),
828 TemplateEncoding => C4::Context->preference("TemplateEncoding"),
829 IndependantBranches=> C4::Context->preference("IndependantBranches"),
830 AutoLocation => C4::Context->preference("AutoLocation"),
831 wrongip => $info{'wrongip'}
834 $template->param( loginprompt => 1 ) unless $info{'nopermission'};
836 my $self_url = $query->url( -absolute => 1 );
839 LibraryName => C4::Context->preference("LibraryName"),
841 $template->param( \%info );
842 # $cookie = $query->cookie(CGISESSID => $session->id
844 print $query->header(
845 -type => 'text/html',
855 ($status, $cookie, $sessionId) = check_api_auth($query, $userflags);
857 Given a CGI query containing the parameters 'userid' and 'password' and/or a session
858 cookie, determine if the user has the privileges specified by C<$userflags>.
860 C<check_api_auth> is is meant for authenticating users of web services, and
861 consequently will always return and will not attempt to redirect the user
864 If a valid session cookie is already present, check_api_auth will return a status
865 of "ok", the cookie, and the Koha session ID.
867 If no session cookie is present, check_api_auth will check the 'userid' and 'password
868 parameters and create a session cookie and Koha session if the supplied credentials
871 Possible return values in C<$status> are:
875 =item "ok" -- user authenticated; C<$cookie> and C<$sessionid> have valid values.
877 =item "failed" -- credentials are not correct; C<$cookie> and C<$sessionid> are undef
879 =item "maintenance" -- DB is in maintenance mode; no login possible at the moment
881 =item "expired -- session cookie has expired; API user should resubmit userid and password
889 my $flagsrequired = shift;
891 my $dbh = C4::Context->dbh;
892 my $timeout = C4::Context->preference('timeout');
893 $timeout = 600 unless $timeout;
895 unless (C4::Context->preference('Version')) {
896 # database has not been installed yet
897 return ("maintenance", undef, undef);
899 my $kohaversion=C4::Context::KOHAVERSION;
900 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
901 if (C4::Context->preference('Version') < $kohaversion) {
902 # database in need of version update; assume that
903 # no API should be called while databsae is in
905 return ("maintenance", undef, undef);
908 # FIXME -- most of what follows is a copy-and-paste
909 # of code from checkauth. There is an obvious need
910 # for refactoring to separate the various parts of
911 # the authentication code, but as of 2007-11-19 this
912 # is deferred so as to not introduce bugs into the
913 # regular authentication code for Koha 3.0.
915 # see if we have a valid session cookie already
916 # however, if a userid parameter is present (i.e., from
917 # a form submission, assume that any current cookie
919 my $sessionID = undef;
920 unless ($query->param('userid')) {
921 $sessionID = $query->cookie("CGISESSID");
924 my $session = get_session($sessionID);
925 C4::Context->_new_userenv($sessionID);
927 C4::Context::set_userenv(
928 $session->param('number'), $session->param('id'),
929 $session->param('cardnumber'), $session->param('firstname'),
930 $session->param('surname'), $session->param('branch'),
931 $session->param('branchname'), $session->param('flags'),
932 $session->param('emailaddress'), $session->param('branchprinter')
935 my $ip = $session->param('ip');
936 my $lasttime = $session->param('lasttime');
937 my $userid = $session->param('id');
938 if ( $lasttime < time() - $timeout ) {
941 C4::Context->_unset_userenv($sessionID);
944 return ("expired", undef, undef);
945 } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
948 C4::Context->_unset_userenv($sessionID);
951 return ("expired", undef, undef);
953 my $cookie = $query->cookie( CGISESSID => $session->id );
954 $session->param('lasttime',time());
955 my $flags = haspermission( $dbh, $userid, $flagsrequired );
957 return ("ok", $cookie, $sessionID);
960 C4::Context->_unset_userenv($sessionID);
963 return ("failed", undef, undef);
967 return ("expired", undef, undef);
971 my $userid = $query->param('userid');
972 my $password = $query->param('password');
973 unless ($userid and $password) {
974 # caller did something wrong, fail the authenticateion
975 return ("failed", undef, undef);
977 my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
978 if ($return and haspermission( $dbh, $userid, $flagsrequired)) {
979 my $session = get_session("");
980 return ("failed", undef, undef) unless $session;
982 my $sessionID = $session->id;
983 C4::Context->_new_userenv($sessionID);
984 my $cookie = $query->cookie(CGISESSID => $sessionID);
985 if ( $return == 1 ) {
987 $borrowernumber, $firstname, $surname,
988 $userflags, $branchcode, $branchname,
989 $branchprinter, $emailaddress
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 userid=?"
995 $sth->execute($userid);
997 $borrowernumber, $firstname, $surname,
998 $userflags, $branchcode, $branchname,
999 $branchprinter, $emailaddress
1000 ) = $sth->fetchrow if ( $sth->rows );
1002 unless ($sth->rows ) {
1003 my $sth = $dbh->prepare(
1004 "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=?"
1006 $sth->execute($cardnumber);
1008 $borrowernumber, $firstname, $surname,
1009 $userflags, $branchcode, $branchname,
1010 $branchprinter, $emailaddress
1011 ) = $sth->fetchrow if ( $sth->rows );
1013 unless ( $sth->rows ) {
1014 $sth->execute($userid);
1016 $borrowernumber, $firstname, $surname, $userflags,
1017 $branchcode, $branchname, $branchprinter, $emailaddress
1018 ) = $sth->fetchrow if ( $sth->rows );
1022 my $ip = $ENV{'REMOTE_ADDR'};
1023 # if they specify at login, use that
1024 if ($query->param('branch')) {
1025 $branchcode = $query->param('branch');
1026 $branchname = GetBranchName($branchcode);
1028 my $branches = GetBranches();
1030 foreach my $br ( keys %$branches ) {
1031 # now we work with the treatment of ip
1032 my $domain = $branches->{$br}->{'branchip'};
1033 if ( $domain && $ip =~ /^$domain/ ) {
1034 $branchcode = $branches->{$br}->{'branchcode'};
1036 # new op dev : add the branchprinter and branchname in the cookie
1037 $branchprinter = $branches->{$br}->{'branchprinter'};
1038 $branchname = $branches->{$br}->{'branchname'};
1041 $session->param('number',$borrowernumber);
1042 $session->param('id',$userid);
1043 $session->param('cardnumber',$cardnumber);
1044 $session->param('firstname',$firstname);
1045 $session->param('surname',$surname);
1046 $session->param('branch',$branchcode);
1047 $session->param('branchname',$branchname);
1048 $session->param('flags',$userflags);
1049 $session->param('emailaddress',$emailaddress);
1050 $session->param('ip',$session->remote_addr());
1051 $session->param('lasttime',time());
1052 } elsif ( $return == 2 ) {
1053 #We suppose the user is the superlibrarian
1054 $session->param('number',0);
1055 $session->param('id',C4::Context->config('user'));
1056 $session->param('cardnumber',C4::Context->config('user'));
1057 $session->param('firstname',C4::Context->config('user'));
1058 $session->param('surname',C4::Context->config('user'));
1059 $session->param('branch','NO_LIBRARY_SET');
1060 $session->param('branchname','NO_LIBRARY_SET');
1061 $session->param('flags',1);
1062 $session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
1063 $session->param('ip',$session->remote_addr());
1064 $session->param('lasttime',time());
1066 C4::Context::set_userenv(
1067 $session->param('number'), $session->param('id'),
1068 $session->param('cardnumber'), $session->param('firstname'),
1069 $session->param('surname'), $session->param('branch'),
1070 $session->param('branchname'), $session->param('flags'),
1071 $session->param('emailaddress'), $session->param('branchprinter')
1073 return ("ok", $cookie, $sessionID);
1075 return ("failed", undef, undef);
1080 =item check_cookie_auth
1082 ($status, $sessionId) = check_api_auth($cookie, $userflags);
1084 Given a CGISESSID cookie set during a previous login to Koha, determine
1085 if the user has the privileges specified by C<$userflags>.
1087 C<check_cookie_auth> is meant for authenticating special services
1088 such as tools/upload-file.pl that are invoked by other pages that
1089 have been authenticated in the usual way.
1091 Possible return values in C<$status> are:
1095 =item "ok" -- user authenticated; C<$sessionID> have valid values.
1097 =item "failed" -- credentials are not correct; C<$sessionid> are undef
1099 =item "maintenance" -- DB is in maintenance mode; no login possible at the moment
1101 =item "expired -- session cookie has expired; API user should resubmit userid and password
1107 sub check_cookie_auth {
1109 my $flagsrequired = shift;
1111 my $dbh = C4::Context->dbh;
1112 my $timeout = C4::Context->preference('timeout');
1113 $timeout = 600 unless $timeout;
1115 unless (C4::Context->preference('Version')) {
1116 # database has not been installed yet
1117 return ("maintenance", undef);
1119 my $kohaversion=C4::Context::KOHAVERSION;
1120 $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
1121 if (C4::Context->preference('Version') < $kohaversion) {
1122 # database in need of version update; assume that
1123 # no API should be called while databsae is in
1125 return ("maintenance", undef);
1128 # FIXME -- most of what follows is a copy-and-paste
1129 # of code from checkauth. There is an obvious need
1130 # for refactoring to separate the various parts of
1131 # the authentication code, but as of 2007-11-23 this
1132 # is deferred so as to not introduce bugs into the
1133 # regular authentication code for Koha 3.0.
1135 # see if we have a valid session cookie already
1136 # however, if a userid parameter is present (i.e., from
1137 # a form submission, assume that any current cookie
1139 unless (defined $cookie and $cookie) {
1140 return ("failed", undef);
1142 my $sessionID = $cookie;
1143 my $session = get_session($sessionID);
1144 C4::Context->_new_userenv($sessionID);
1146 C4::Context::set_userenv(
1147 $session->param('number'), $session->param('id'),
1148 $session->param('cardnumber'), $session->param('firstname'),
1149 $session->param('surname'), $session->param('branch'),
1150 $session->param('branchname'), $session->param('flags'),
1151 $session->param('emailaddress'), $session->param('branchprinter')
1154 my $ip = $session->param('ip');
1155 my $lasttime = $session->param('lasttime');
1156 my $userid = $session->param('id');
1157 if ( $lasttime < time() - $timeout ) {
1160 C4::Context->_unset_userenv($sessionID);
1163 return ("expired", undef);
1164 } elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
1165 # IP address changed
1167 C4::Context->_unset_userenv($sessionID);
1170 return ("expired", undef);
1172 $session->param('lasttime',time());
1173 my $flags = haspermission( $dbh, $userid, $flagsrequired );
1175 return ("ok", $sessionID);
1178 C4::Context->_unset_userenv($sessionID);
1181 return ("failed", undef);
1185 return ("expired", undef);
1192 my $session = get_session($sessionID);
1194 Given a session ID, retrieve the CGI::Session object used to store
1195 the session's state. The session object can be used to store
1196 data that needs to be accessed by different scripts during a
1199 If the C<$sessionID> parameter is an empty string, a new session
1205 my $sessionID = shift;
1206 my $storage_method = C4::Context->preference('SessionStorage');
1207 my $dbh = C4::Context->dbh;
1209 if ($storage_method eq 'mysql'){
1210 $session = new CGI::Session("driver:MySQL;serializer:yaml;id:md5", $sessionID, {Handle=>$dbh});
1212 elsif ($storage_method eq 'Pg') {
1213 $session = new CGI::Session("driver:PostgreSQL;serializer:yaml;id:md5", $sessionID, {Handle=>$dbh});
1216 # catch all defaults to tmp should work on all systems
1217 $session = new CGI::Session("driver:File;serializer:yaml;id:md5", $sessionID, {Directory=>'/tmp'});
1224 my ( $dbh, $userid, $password ) = @_;
1226 $debug and print STDERR "## checkpw - checking LDAP\n";
1227 my ($retval,$retcard) = checkpw_ldap(@_); # EXTERNAL AUTH
1228 ($retval) and return ($retval,$retcard);
1234 "select password,cardnumber,borrowernumber,userid,firstname,surname,branchcode,flags from borrowers where userid=?"
1236 $sth->execute($userid);
1238 my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
1239 $surname, $branchcode, $flags )
1241 if ( md5_base64($password) eq $md5password ) {
1243 C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
1244 $firstname, $surname, $branchcode, $flags );
1245 return 1, $cardnumber;
1250 "select password,cardnumber,borrowernumber,userid, firstname,surname,branchcode,flags from borrowers where cardnumber=?"
1252 $sth->execute($userid);
1254 my ( $md5password, $cardnumber, $borrowernumber, $userid, $firstname,
1255 $surname, $branchcode, $flags )
1257 if ( md5_base64($password) eq $md5password ) {
1259 C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
1260 $firstname, $surname, $branchcode, $flags );
1264 if ( $userid && $userid eq C4::Context->config('user')
1265 && "$password" eq C4::Context->config('pass') )
1268 # Koha superuser account
1269 # C4::Context->set_userenv(0,0,C4::Context->config('user'),C4::Context->config('user'),C4::Context->config('user'),"",1);
1272 if ( $userid && $userid eq 'demo'
1273 && "$password" eq 'demo'
1274 && C4::Context->config('demo') )
1277 # DEMO => the demo user is allowed to do everything (if demo set to 1 in koha.conf
1278 # some features won't be effective : modify systempref, modify MARC structure,
1286 $authflags = getuserflags($flags,$dbh);
1287 Translates integer flags into permissions strings hash.
1289 C<$flags> is the integer userflags value ( borrowers.userflags )
1290 C<$authflags> is a hashref of permissions
1299 $flags = 0 unless $flags;
1300 my $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
1303 while ( my ( $bit, $flag, $defaulton ) = $sth->fetchrow ) {
1304 if ( ( $flags & ( 2**$bit ) ) || $defaulton ) {
1305 $userflags->{$flag} = 1;
1308 $userflags->{$flag} = 0;
1312 # get subpermissions and merge with top-level permissions
1313 my $user_subperms = get_user_subpermissions($userid);
1314 foreach my $module (keys %$user_subperms) {
1315 next if $userflags->{$module} == 1; # user already has permission for everything in this module
1316 $userflags->{$module} = $user_subperms->{$module};
1322 =item get_user_subpermissions
1326 my $user_perm_hashref = get_user_subpermissions($userid);
1330 Given the userid (note, not the borrowernumber) of a staff user,
1331 return a hashref of hashrefs of the specific subpermissions
1332 accorded to the user. An example return is
1336 export_catalog => 1,
1337 import_patrons => 1,
1341 The top-level hash-key is a module or function code from
1342 userflags.flag, while the second-level key is a code
1345 The results of this function do not give a complete picture
1346 of the functions that a staff user can access; it is also
1347 necessary to check borrowers.flags.
1351 sub get_user_subpermissions {
1354 my $dbh = C4::Context->dbh;
1355 my $sth = $dbh->prepare("SELECT flag, user_permissions.code
1356 FROM user_permissions
1357 JOIN permissions USING (module_bit, code)
1358 JOIN userflags ON (module_bit = bit)
1359 JOIN borrowers USING (borrowernumber)
1361 $sth->execute($userid);
1363 my $user_perms = {};
1364 while (my $perm = $sth->fetchrow_hashref) {
1365 $user_perms->{$perm->{'flag'}}->{$perm->{'code'}} = 1;
1370 =item get_all_subpermissions
1374 my $perm_hashref = get_all_subpermissions();
1378 Returns a hashref of hashrefs defining all specific
1379 permissions currently defined. The return value
1380 has the same structure as that of C<get_user_subpermissions>,
1381 except that the innermost hash value is the description
1382 of the subpermission.
1386 sub get_all_subpermissions {
1387 my $dbh = C4::Context->dbh;
1388 my $sth = $dbh->prepare("SELECT flag, code, description
1390 JOIN userflags ON (module_bit = bit)");
1394 while (my $perm = $sth->fetchrow_hashref) {
1395 $all_perms->{$perm->{'flag'}}->{$perm->{'code'}} = $perm->{'description'};
1402 $flags = ($dbh,$member,$flagsrequired);
1404 C<$member> may be either userid or overloaded with $borrower hashref from GetMemberDetails.
1405 C<$flags> is a hashref of required flags like C<$borrower-<{authflags}>
1407 Returns member's flags or 0 if a permission is not met.
1412 my ( $dbh, $userid, $flagsrequired ) = @_;
1413 my ($flags,$intflags);
1414 $dbh=C4::Context->dbh unless($dbh);
1416 $intflags = $userid->{'flags'};
1418 my $sth = $dbh->prepare("SELECT flags FROM borrowers WHERE userid=?");
1419 $sth->execute($userid);
1420 my ($intflags) = $sth->fetchrow;
1421 $flags = getuserflags( $intflags, $userid, $dbh );
1423 if ( $userid eq C4::Context->config('user') ) {
1424 # Super User Account from /etc/koha.conf
1425 $flags->{'superlibrarian'} = 1;
1427 if ( $userid eq 'demo' && C4::Context->config('demo') ) {
1428 # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
1429 $flags->{'superlibrarian'} = 1;
1431 return $flags if $flags->{superlibrarian};
1432 foreach my $module ( keys %$flagsrequired ) {
1433 if (C4::Context->preference('GranularPermissions')) {
1434 my $subperm = $flagsrequired->{$module};
1435 if ($subperm eq '*') {
1436 return 0 unless ( $flags->{$module} == 1 or ref($flags->{$module}) );
1438 return 0 unless ( $flags->{$module} == 1 or
1439 ( ref($flags->{$module}) and
1440 exists $flags->{$module}->{$subperm} and
1441 $flags->{$module}->{$subperm} == 1
1446 return 0 unless ( $flags->{$module} );
1450 #FIXME - This fcn should return the failed permission so a suitable error msg can be delivered.
1454 sub getborrowernumber {
1456 my $dbh = C4::Context->dbh;
1457 for my $field ( 'userid', 'cardnumber' ) {
1459 $dbh->prepare("select borrowernumber from borrowers where $field=?");
1460 $sth->execute($userid);
1462 my ($bnumber) = $sth->fetchrow;
1469 END { } # module clean-up code here (global destructor)