#
# This file is part of Koha.
#
-# Koha is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
#
-# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
#
-# You should have received a copy of the GNU General Public License along
-# with Koha; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
use strict;
#use warnings; FIXME - Bug 2505
use C4::Debug;
use C4::Context;
-use C4::Members qw(AddMember changepassword);
+use C4::Members qw(AddMember);
use C4::Members::Attributes;
use C4::Members::AttributeTypes;
use C4::Members::Messaging;
use C4::Auth qw(checkpw_internal);
+use Koha::Patrons;
use Koha::AuthUtils qw(hash_password);
use List::MoreUtils qw( any );
use Net::LDAP;
use Net::LDAP::Filter;
-use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug);
+use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug);
BEGIN {
require Exporter;
- $VERSION = 3.07.00.049; # set the version for version checking
@ISA = qw(Exporter);
@EXPORT = qw( checkpw_ldap );
}
@mapkeys = grep {defined $mapping{$_}->{is}} @mapkeys;
$debug and print STDERR "Got ", scalar(@mapkeys), " ldap mapkeys (populated): ", join ' ', @mapkeys, "\n";
+my %categorycode_conversions;
+my $default_categorycode;
+if(defined $ldap->{categorycode_mapping}) {
+ $default_categorycode = $ldap->{categorycode_mapping}->{default};
+ foreach my $cat (@{$ldap->{categorycode_mapping}->{categorycode}}) {
+ $categorycode_conversions{$cat->{value}} = $cat->{content};
+ }
+}
+
my %config = (
anonymous => ($ldapname and $ldappassword) ? 0 : 1,
replicate => defined($ldap->{replicate}) ? $ldap->{replicate} : 1, # add from LDAP to Koha database for new user
# Perform a LDAP bind for the given username using the matched DN
my $res = $db->bind( $principal_name, password => $password );
if ( $res->code ) {
- warn "LDAP bind failed as kohauser $userid: " . description($res);
- return -1;
+ if ( $ldap->{anonymous_bind} ) {
+ # With anonymous_bind approach we can be sure we have found the correct user
+ # and that any 'code' response indicates a 'bad' user (be that blocked, banned
+ # or password changed). We should not fall back to local accounts in this case.
+ warn "LDAP bind failed as kohauser $userid: " . description($res);
+ return -1;
+ } else {
+ # Without a anonymous_bind, we cannot be sure we are looking at a valid ldap user
+ # at all, and thus we should fall back to local logins to restore previous behaviour
+ # see bug 12831
+ warn "LDAP bind failed as kohauser $userid: " . description($res);
+ return 0;
+ }
}
if ( !defined($userldapentry)
&& ( $config{update} or $config{replicate} ) )
return 0; # B2, D2
}
if (C4::Context->preference('ExtendedPatronAttributes') && $borrowernumber && ($config{update} ||$config{replicate})) {
- my @extended_patron_attributes;
foreach my $attribute_type ( C4::Members::AttributeTypes::GetAttributeTypes() ) {
my $code = $attribute_type->{code};
- if ( exists($borrower{$code}) && $borrower{$code} !~ m/^\s*$/ ) { # skip empty values
- push @extended_patron_attributes, { code => $code, value => $borrower{$code} };
+ unless (exists($borrower{$code}) && $borrower{$code} !~ m/^\s*$/ ) {
+ next;
}
- }
- #Check before add
- my @unique_attr;
- foreach my $attr ( @extended_patron_attributes ) {
- if (C4::Members::Attributes::CheckUniqueness($attr->{code}, $attr->{value}, $borrowernumber)) {
- push @unique_attr, $attr;
+ if (C4::Members::Attributes::CheckUniqueness($code, $borrower{$code}, $borrowernumber)) {
+ C4::Members::Attributes::UpdateBorrowerAttribute($borrowernumber, {code => $code, value => $borrower{$code}});
} else {
- warn "ERROR_extended_unique_id_failed $attr->{code} $attr->{value}";
+ warn "ERROR_extended_unique_id_failed $code $borrower{$code}";
}
}
- C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, \@unique_attr);
}
-return(1, $cardnumber, $userid);
+ return(1, $cardnumber, $userid);
}
# Pass LDAP entry object and local cardnumber (userid).
. substr($borrower{ 'surname' },0,1)
. " ");
+ # categorycode conversions
+ if(defined $categorycode_conversions{$borrower{categorycode}}) {
+ $borrower{categorycode} = $categorycode_conversions{$borrower{categorycode}};
+ }
+ elsif($default_categorycode) {
+ $borrower{categorycode} = $default_categorycode;
+ }
+
# check if categorycode exists, if not, fallback to default from koha-conf.xml
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("SELECT categorycode FROM categories WHERE categorycode = ?");
return 0;
}
+# This function performs a password update, given the userid, borrowerid,
+# and digested password. It will verify that things are correct and return the
+# borrowers cardnumber. The idea is that it is used to keep the local
+# passwords in sync with the LDAP passwords.
+#
+# $cardnum = _do_changepassword($userid, $borrowerid, $digest)
+#
+# Note: if the LDAP config has the update_password tag set to a false value,
+# then this will not update the password, it will simply return the cardnumber.
sub _do_changepassword {
my ($userid, $borrowerid, $password) = @_;
+ if ( exists( $ldap->{update_password} ) && !$ldap->{update_password} ) {
+
+ # We don't store the password in the database
+ my $sth = C4::Context->dbh->prepare(
+ 'SELECT cardnumber FROM borrowers WHERE borrowernumber=?');
+ $sth->execute($borrowerid);
+ die "Unable to access borrowernumber "
+ . "with userid=$userid, "
+ . "borrowernumber=$borrowerid"
+ if !$sth->rows;
+ my ($cardnum) = $sth->fetchrow;
+ $sth = C4::Context->dbh->prepare(
+ 'UPDATE borrowers SET password = null WHERE borrowernumber=?');
+ $sth->execute($borrowerid);
+ return $cardnum;
+ }
my $digest = hash_password($password);
$debug and print STDERR "changing local password for borrowernumber=$borrowerid to '$digest'\n";
- changepassword($userid, $borrowerid, $digest);
+ Koha::Patrons->find($borrowerid)->update_password( $userid, $digest );
my ($ok, $cardnum) = checkpw_internal(C4::Context->dbh, $userid, $password);
return $cardnum if $ok;
<principal_name>%s@my_domain.com</principal_name>
<!-- optional, for auth_by_bind: a printf format to make userPrincipalName from koha userid.
Not used with anonymous_bind. -->
-
+ <update_password>1</update_password> <!-- set to 0 if you don't want LDAP passwords
+ synced to the local database -->
<mapping> <!-- match koha SQL field names to your LDAP record field names -->
<firstname is="givenname" ></firstname>
<surname is="sn" ></surname>
Currently, principal_name only operates when auth_by_bind is enabled.
+=head2 update_password
+
+If this tag is left out or set to a true value, then the user's LDAP password
+will be stored (hashed) in the local Koha database. If you don't want this
+to happen, then set the value of this to '0'. Note that if passwords are not
+stored locally, and the connection to the LDAP system fails, then the users
+will not be able to log in at all.
+
=head2 Active Directory
The auth_by_bind and principal_name settings are recommended for Active Directory.