Overview

Packages

  • None
  • Passwd

Classes

  • Passwd
  • Passwd_Driver
  • Passwd_Driver_Adsi
  • Passwd_Driver_Composite
  • Passwd_Driver_Expect
  • Passwd_Driver_Expectpecl
  • Passwd_Driver_Horde
  • Passwd_Driver_Http
  • Passwd_Driver_Kolab
  • Passwd_Driver_Ldap
  • Passwd_Driver_Pine
  • Passwd_Driver_Poppassd
  • Passwd_Driver_Procopen
  • Passwd_Driver_Pspasswd
  • Passwd_Driver_Servuftp
  • Passwd_Driver_Smbldap
  • Passwd_Driver_Smbpasswd
  • Passwd_Driver_Soap
  • Passwd_Driver_Sql
  • Passwd_Driver_Vmailmgr
  • Passwd_Driver_Vpopmail
  • Passwd_Exception
  • Passwd_Factory_Driver
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The LDAP class attempts to change a user's password stored in an LDAP
  4:  * directory service.
  5:  *
  6:  * Copyright 2000-2012 Horde LLC (http://www.horde.org/)
  7:  *
  8:  * See http://www.horde.org/licenses/gpl.php for license information (GPL).
  9:  *
 10:  * @author  Mike Cochrane <mike@graftonhall.co.nz>
 11:  * @author  Tjeerd van der Zee <admin@xar.nl>
 12:  * @author  Mattias Webjörn Eriksson <mattias@webjorn.org>
 13:  * @author  Eric Jon Rostetter <eric.rostetter@physics.utexas.edu>
 14:  * @author  Ralf Lang <lang@b1-systems.de>
 15:  * @author  Jan Schneider <jan@horde.org>
 16:  * @package Passwd
 17:  */
 18: class Passwd_Driver_Ldap extends Passwd_Driver
 19: {
 20:     /**
 21:      * LDAP object.
 22:      *
 23:      * @var resource
 24:      */
 25:     protected $_ldap = false;
 26: 
 27:     /**
 28:      * The user's DN.
 29:      *
 30:      * @var string
 31:      */
 32:     protected $_userdn;
 33: 
 34:     /**
 35:      * Constructor.
 36:      *
 37:      * @param array $params  A hash containing connection parameters.
 38:      *
 39:      * @throws InvalidArgumentException
 40:      */
 41:     public function __construct($params = array())
 42:     {
 43:         foreach (array('basedn', 'ldap', 'uid') as $val) {
 44:             if (!isset($params[$val])) {
 45:                 throw new InvalidArgumentException(__CLASS__ . ': Missing ' . $val . ' parameter.');
 46:             }
 47:         }
 48: 
 49:         $this->_ldap = $params['ldap'];
 50:         unset($params['ldap']);
 51: 
 52:         $this->_params = array_merge(
 53:             array('host' => 'localhost',
 54:                   'port' => 389,
 55:                   'encryption' => 'crypt',
 56:                   'show_encryption' => 'true',
 57:                   'uid' => 'uid',
 58:                   'basedn' => '',
 59:                   'admindn' => '',
 60:                   'adminpw' => '',
 61:                   'realm' => '',
 62:                   'filter' => null,
 63:                   'tls' => false,
 64:                   'attribute' => 'userPassword',
 65:                   'shadowlastchange' => '',
 66:                   'shadowmin' => ''),
 67:             $params);
 68: 
 69:         if (!empty($this->_params['tls']) &&
 70:             empty($this->_params['sslhost'])) {
 71:             $this->_params['sslhost'] = $this->_params['host'];
 72:         }
 73:     }
 74: 
 75:     /**
 76:      * Compares a plaintext password with an encrypted password.
 77:      *
 78:      * @param string $encrypted  An encrypted password.
 79:      * @param string $plaintext  An unencrypted password.
 80:      *
 81:      * @throws Passwd_Exception if passwords don't match.
 82:      */
 83:     protected function _comparePasswords($encrypted, $plaintext)
 84:     {
 85:         $encrypted = preg_replace('/^{MD5}(.*)/i', '{MD5-BASE64}$1', $encrypted);
 86:         return parent::_comparePasswords($encrypted, $plaintext);
 87:     }
 88: 
 89:     /**
 90:      * Changes the user's password.
 91:      *
 92:      * @param string $username      The user for which to change the password.
 93:      * @param string $old_password  The old (current) user password.
 94:      * @param string $new_password  The new user password to set.
 95:      *
 96:      * @throws Passwd_Exception
 97:      */
 98:     public function changePassword($username, $old_password, $new_password)
 99:     {
100:         // Append realm as username@realm if 'realm' parameter is set.
101:         if (!empty($this->_params['realm'])) {
102:             $username .= '@' . $this->_params['realm'];
103:         }
104: 
105:         // Get the user's dn from hook or fall back to Horde_Ldap::findUserDN.
106:         try {
107:             $this->_userdn = Horde::callHook('userdn', array($username), 'passwd');
108:         } catch (Horde_Exception_HookNotSet $e) {
109:             // @todo Fix finding the user DN.
110:             // $this->_userdn = $this->_ldap->findUserDN($username);
111:             // workaround
112:             $this->_userdn = $this->_params['uid'] . '=' . $username . ',' . $this->_params['basedn'];
113:         }
114: 
115:         try {
116:             // Check the old password by binding as the userdn.
117:             $this->_ldap->bind($this->_userdn, $old_password);
118:         } catch (Horde_Ldap_Exception $e) {
119:             throw new Passwd_Exception($e);
120:         }
121: 
122:         // Rebind with admin credentials.
123:         if (!empty($this->_params['admindn'])) {
124:             try {
125:                 $this->_ldap->bind();
126:             } catch (Horde_Ldap_Exception $e) {
127:                 throw new Passwd_Exception($e);
128:             }
129:         }
130: 
131:         // Get existing user information.
132:         $entry = $this->_getUserEntry();
133:         if (!$entry) {
134:              throw new Passwd_Exception(_("User not found."));
135:         }
136: 
137:         // Init the shadow policy array.
138:         $lookupshadow = array('shadowlastchange' => false,
139:                               'shadowmin' => false);
140: 
141:         if (!empty($this->_params['shadowlastchange']) &&
142:             $entry->exists($this->_params['shadowlastchange'])) {
143:             $lookupshadow['shadowlastchange'] = $entry->getValue($this->_params['shadowlastchange']);            
144:         }
145:         if (!empty($this->_params['shadowmin']) &&
146:             $entry->exists($this->_params['shadowmin'])) {
147:             $lookupshadow['shadowmin'] = $entry->getValue($this->_params['shadowmin']);            
148:         }
149: 
150:         // Check if we may change the password.
151:         if ($lookupshadow['shadowlastchange'] &&
152:             $lookupshadow['shadowmin'] &&
153:             ($lookupshadow['shadowlastchange'] + $lookupshadow['shadowmin'] > (time() / 86400))) {
154:             throw new Passwd_Exception(_("Minimum password age has not yet expired"));
155:         }
156: 
157:         // Change the user's password and update lastchange.
158:         try {
159:             $entry->replace(array($this->_params['attribute'] => $this->_encryptPassword($new_password)), true);
160: 
161:             if (!empty($this->_params['shadowlastchange']) &&
162:                 $lookupshadow['shadowlastchange']) {
163:                 $entry->replace(array($this->_params['shadowlastchange'] => floor(time() / 86400)));
164:             }
165: 
166:             $entry->update();
167:         } catch (Horde_Ldap_Exception $e) {
168:             throw new Passwd_Exception($e);
169:         }
170:     }
171: 
172:     /**
173:      * Returns the LDAP entry for the user.
174:      *
175:      * @return Horde_Ldap_Entry  The user's LDAP entry if it exists.
176:      * @throws Passwd_Exception
177:      */
178:     protected function _getUserEntry()
179:     {
180:         try {
181:             return $this->_ldap->getEntry($this->_userdn);
182:         } catch (Horde_Ldap_Exception $e) {
183:             throw new Passwd_Exception($e);
184:         }
185:     }
186: }
187: 
API documentation generated by ApiGen