wiki-archive/twiki/lib/TWiki/Users/LdapPasswdUser.pm

220 lines
5.6 KiB
Perl
Raw Normal View History

# Module of TWiki Enterprise Collaboration Platform, http://TWiki.org/
#
# Copyright (C) 2004-2007 TWiki Contributors. All Rights Reserved.
# TWiki Contributors are listed in the AUTHORS file in the root of
# this distribution. NOTE: Please extend that file, not this notice.
#
# This program 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. For
# more details read LICENSE in the root of this distribution.
#
# This program 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.
#
# As per the GPL, removal of this notice is prohibited.
package TWiki::Users::LdapPasswdUser;
use Net::LDAP;
use Assert;
use strict;
use TWiki::Users::Password;
use Error qw( :try );
@TWiki::Users::LdapPasswdUser::ISA = qw( TWiki::Users::Password );
=pod
---+ package TWiki::Users::LdapPasswdUser
Password manager that uses LDAP to manage users and passwords.
Subclass of [[TWikiUsersPasswordDotPm][ =TWiki::Users::Password= ]].
See documentation of that class for descriptions of the methods of this class.
=cut
sub new {
my( $class, $session ) = @_;
my $this = bless( $class->SUPER::new( $session ), $class );
$this->{error} = undef;
if( $TWiki::cfg{LdapPasswd}{Encoding} eq 'md5' ) {
require Digest::MD5;
} elsif( $TWiki::cfg{LdapPasswd}{Encoding} eq 'sha1' ) {
require MIME::Base64;
import MIME::Base64 qw( encode_base64 );
require Digest::SHA1;
import Digest::SHA1 qw( sha1 );
}
return $this;
}
sub encrypt {
my ( $this, $user, $passwd, $fresh ) = @_;
ASSERT($this->isa( 'TWiki::Users::LdapPasswdUser')) if DEBUG;
$passwd ||= '';
if( $TWiki::cfg{LdapPasswd}{Encoding} eq 'sha1') {
my $encodedPassword = '{SHA}'.
MIME::Base64::encode_base64( Digest::SHA1::sha1( $passwd ) );
# don't use chomp, it relies on $/
$encodedPassword =~ s/\s+$//;
return $encodedPassword;
} elsif ( $TWiki::cfg{LdapPasswd}{Encoding} eq 'crypt' ) {
# by David Levy, Internet Channel, 1997
# found at http://world.inch.com/Scripts/htpasswd.pl.html
my $salt;
$salt = $this->fetchPass( $user ) unless $fresh;
if ( $fresh || !$salt ) {
my @saltchars = ( 'a'..'z', 'A'..'Z', '0'..'9', '.', '/' );
$salt = $saltchars[int(rand($#saltchars+1))] .
$saltchars[int(rand($#saltchars+1)) ];
}
return crypt( $passwd, substr( $salt, 0, 2 ) );
} elsif ( $TWiki::cfg{LdapPasswd}{Encoding} eq 'md5' ) {
# SMELL: what does this do if we are using a htpasswd file?
my $toEncode= "$user:$TWiki::cfg{AuthRealm}:$passwd";
return Digest::MD5::md5_hex( $toEncode );
} elsif ( $TWiki::cfg{LdapPasswd}{Encoding} eq 'plain' ) {
return $passwd;
}
die 'Unsupported password encoding '.
$TWiki::cfg{LdapPasswd}{Encoding};
}
sub _getLdapEntry {
my ( $this, $user ) = @_;
ASSERT($this->isa( 'TWiki::Users::LdapPasswdUser')) if DEBUG;
$this->{error} = undef;
# create LDAP object
$this->{ldap} = Net::LDAP->new($TWiki::cfg{LdapPasswd}{Host});
if (!$this->{ldap}) {
$this->{error} = "$@";
return;
}
$this->{ldap}->bind(
$TWiki::cfg{LdapPasswd}{AdminDN},
password => $TWiki::cfg{LdapPasswd}{AdminPwd}
);
if (!defined $this->{ldap}) {
$this->{error} = 'Couldn\'t contact LDAP server...';
return;
}
# perform a search
my $entries = $this->{ldap}->search(
base => $TWiki::cfg{LdapPasswd}{BaseDN},
filter => "(& (uid=$user) (!(employeeType=*Disabled*)))"
);
if (!($entries->error eq "Success")) {
$this->{error} = $entries->error;
}
my $entry = $entries->entry(0);
$this->{ldap}->unbind; # take down session
return $entry;
}
sub fetchPass {
my ( $this, $user ) = @_;
ASSERT($this->isa( 'TWiki::Users::LdapPasswdUser')) if DEBUG;
my $ret = undef;
if( $user ) {
my $entry = $this->_getLdapEntry($user);
if( $entry && ($entry->get_value("uid") eq $user)) {
$ret = $entry->get_value("userPassword");
} else {
$this->{error} = 'Login invalid';
}
} else {
$this->{error} = 'No user';
}
return $ret;
}
sub checkPassword {
my ( $this, $user, $password ) = @_;
ASSERT($this->isa( 'TWiki::Users::LdapPasswdUser')) if DEBUG;
my $encryptedPassword = $this->encrypt( $user, $password );
#die "User: $user";
#die "UPwd: $password";
#die "EPwd: $encryptedPassword";
$this->{error} = undef;
my $pw = $this->fetchPass( $user );
return 0 unless defined $pw;
# $pw will be 0 if there is no pw
return 1 if( $pw && ($encryptedPassword eq $pw) );
# pw may validly be '', and must match an unencrypted ''. This is
# to allow for sysadmins removing the password field in .htpasswd in
# order to reset the password.
return 1 if ( defined $password && $pw eq '' && $password eq '' );
$this->{error} = 'Invalid user/password';
return 0;
}
sub error {
my $this = shift;
return $this->{error} || undef;
}
sub getEmails {
my( $this, $login) = @_;
my $entry = $this->_getLdapEntry($login);
my @addresses;
if (defined $entry) {
push( @addresses, $entry->get_value("mail") );
} else {
# this warning message will show up on cron output log
print "LdapPasswdUser.pm: Couldn't find LDAP record for user $login\n";
print "LdapPasswdUser.pm: Error message: " . $this->{error} . "\n";
}
return @addresses;
}
1;