Files
server/usr/share/psa-horde/passwd/lib/Driver/Ldap.php
2026-01-07 20:52:11 +01:00

187 lines
5.8 KiB
PHP

<?php
/**
* Copyright 2000-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (GPL). If you
* did not receive this file, see http://www.horde.org/licenses/gpl.
*
* @category Horde
* @copyright 2000-2017 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package Passwd
*/
/**
* The LDAP class attempts to change a user's password stored in an LDAP
* directory service.
*
* @author Mike Cochrane <mike@graftonhall.co.nz>
* @author Mattias Webjörn Eriksson <mattias@webjorn.org>
* @author Ralf Lang <lang@b1-systems.de>
* @author Eric Jon Rostetter <eric.rostetter@physics.utexas.edu>
* @author Jan Schneider <jan@horde.org>
* @author Tjeerd van der Zee <admin@xar.nl>
* @category Horde
* @copyright 2000-2017 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package Passwd
*/
class Passwd_Driver_Ldap extends Passwd_Driver
{
/**
* LDAP object.
*
* @var resource
*/
protected $_ldap = false;
/**
* The user's DN.
*
* @var string
*/
protected $_userdn;
/**
*/
public function __construct(array $params = array())
{
foreach (array('basedn', 'ldap', 'uid') as $val) {
if (!isset($params[$val])) {
throw new InvalidArgumentException(__CLASS__ . ': Missing ' . $val . ' parameter.');
}
}
$this->_ldap = $params['ldap'];
unset($params['ldap']);
parent::__construct(array_merge(array(
'host' => 'localhost',
'port' => 389,
'encryption' => 'crypt',
'show_encryption' => 'true',
'uid' => 'uid',
'basedn' => '',
'admindn' => '',
'adminpw' => '',
'realm' => '',
'filter' => null,
'tls' => false,
'attribute' => 'userPassword',
'shadowlastchange' => '',
'shadowmin' => ''
), $params));
if (!empty($this->_params['tls']) &&
empty($this->_params['sslhost'])) {
$this->_params['sslhost'] = $this->_params['host'];
}
}
/**
* Compares a plaintext password with an encrypted password.
*
* @param string $encrypted An encrypted password.
* @param string $plaintext An unencrypted password.
*
* @throws Passwd_Exception if passwords don't match.
*/
protected function _comparePasswords($encrypted, $plaintext)
{
$encrypted = preg_replace('/^{MD5}(.*)/i', '{MD5-BASE64}$1', $encrypted);
return parent::_comparePasswords($encrypted, $plaintext);
}
/**
*/
protected function _changePassword($user, $oldpass, $newpass)
{
global $injector;
// Append realm as username@realm if 'realm' parameter is set.
if (!empty($this->_params['realm'])) {
$user .= '@' . $this->_params['realm'];
}
// Try to get the user's dn from config.
if (isset($this->_params['userdn'])) {
$this->_userdn = str_replace('%u', $user, $this->_params['userdn']);
} else {
try {
$this->_userdn = $injector->getInstance('Horde_Core_Hooks')->callHook(
'userdn',
'passwd',
array($user)
);
} catch (Horde_Exception_HookNotSet $e) {
// @todo Fix finding the user DN.
// $this->_userdn = $this->_ldap->findUserDN($user);
$this->_userdn = $this->_params['uid'] . '=' . $user . ',' . $this->_params['basedn'];
}
}
try {
// Check the old password by binding as the userdn.
$this->_ldap->bind($this->_userdn, $oldpass);
} catch (Horde_Ldap_Exception $e) {
throw new Passwd_Exception($e);
}
// Rebind with admin credentials.
if (!empty($this->_params['admindn'])) {
try {
$this->_ldap->bind();
} catch (Horde_Ldap_Exception $e) {
throw new Passwd_Exception($e);
}
}
// Get existing user information.
try {
if (!($entry = $this->_ldap->getEntry($this->_userdn))) {
throw new Passwd_Exception(_("User not found."));
}
} catch (Horde_Ldap_Exception $e) {
throw new Passwd_Exception($e);
}
// Init the shadow policy array.
$lookupshadow = array(
'shadowlastchange' => false,
'shadowmin' => false
);
foreach (array_keys($lookupshadow) as $val) {
if (!empty($this->_params[$val]) &&
$entry->exists($this->_params[$val])) {
$lookupshadow[$val] = $entry->getValue($this->_params[$val]);
}
}
// Check if we may change the password.
if ($lookupshadow['shadowlastchange'] &&
$lookupshadow['shadowmin'] &&
(($lookupshadow['shadowlastchange'] + $lookupshadow['shadowmin']) > (time() / 86400))) {
throw new Passwd_Exception(_("Minimum password age has not yet expired"));
}
// Change the user's password and update lastchange.
try {
$entry->replace(array(
$this->_params['attribute'] => $this->_encryptPassword($newpass)
), true);
if (!empty($this->_params['shadowlastchange']) &&
$lookupshadow['shadowlastchange']) {
$entry->replace(array(
$this->_params['shadowlastchange'] => floor(time() / 86400)
));
}
$entry->update();
} catch (Horde_Ldap_Exception $e) {
throw new Passwd_Exception($e);
}
}
}