/passwd/lib/Driver/Ldap.php

https://github.com/finger2000/horde · PHP · 150 lines · 81 code · 16 blank · 53 comment · 9 complexity · c5ca7926b231207e0ddd49e1403079c3 MD5 · raw file

  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-2011 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. * The user's DN.
  28. *
  29. * @var string
  30. */
  31. protected $_userdn;
  32. /**
  33. * Constructor.
  34. *
  35. * @param array $params A hash containing connection parameters.
  36. *
  37. * @throws InvalidArgumentException
  38. */
  39. public function __construct($params = array())
  40. {
  41. foreach (array('basedn', 'ldap', 'uid') as $val) {
  42. if (!isset($params[$val])) {
  43. throw new InvalidArgumentException(__CLASS__ . ': Missing ' . $val . ' parameter.');
  44. }
  45. }
  46. $this->_ldap = $params['ldap'];
  47. unset($params['ldap']);
  48. $this->_params = array_merge(
  49. array('host' => 'localhost',
  50. 'port' => 389,
  51. 'encryption' => 'crypt',
  52. 'show_encryption' => 'true',
  53. 'uid' => 'uid',
  54. 'basedn' => '',
  55. 'admindn' => '',
  56. 'adminpw' => '',
  57. 'realm' => '',
  58. 'filter' => null,
  59. 'tls' => false,
  60. 'attribute' => 'userPassword',
  61. 'shadowlastchange' => '',
  62. 'shadowmin' => ''),
  63. $params);
  64. if (!empty($this->_params['tls']) &&
  65. empty($this->_params['sslhost'])) {
  66. $this->_params['sslhost'] = $this->_params['host'];
  67. }
  68. }
  69. /**
  70. * Changes the user's password.
  71. *
  72. * @param string $username The user for which to change the password.
  73. * @param string $old_password The old (current) user password.
  74. * @param string $new_password The new user password to set.
  75. *
  76. * @throws Passwd_Exception if changing the password failed.
  77. */
  78. public function changePassword($username, $old_password, $new_password)
  79. {
  80. // Append realm as username@realm if 'realm' parameter is set.
  81. if (!empty($this->_params['realm'])) {
  82. $username .= '@' . $this->_params['realm'];
  83. }
  84. // Get the user's dn from hook or fall back to Horde_Ldap::findUserDN.
  85. try {
  86. $this->_userdn = Horde::callHook('userdn', array($username), 'passwd');
  87. } catch (Horde_Exception_HookNotSet $e) {
  88. // @todo Fix finding the user DN.
  89. // $this->_userdn = $this->_ldap->findUserDN($username);
  90. // workaround
  91. $this->_userdn = $this->_params['uid'] . '=' . $username . ',' . $this->_params['basedn'];
  92. }
  93. // Check the old password by binding as the userdn.
  94. $this->_ldap->bind($this->_userdn, $old_password);
  95. // Rebind with admin credentials.
  96. if (!empty($this->_params['admindn'])) {
  97. $this->_ldap->bind();
  98. }
  99. // Get existing user information.
  100. $entry = $this->_ldap->search($this->_userdn, $this->_params['filter'])
  101. ->shiftEntry();
  102. if (!$entry) {
  103. throw new Passwd_Exception(_("User not found."));
  104. }
  105. // Init the shadow policy array.
  106. $lookupshadow = array('shadowlastchange' => false,
  107. 'shadowmin' => false);
  108. if (!empty($this->_params['shadowlastchange']) &&
  109. $entry->exists($this->_params['shadowlastchange'])) {
  110. $lookupshadow['shadowlastchange'] = $entry->getValue($this->_params['shadowlastchange']);
  111. }
  112. if (!empty($this->_params['shadowmin']) &&
  113. $entry->exists($this->_params['shadowmin'])) {
  114. $lookupshadow['shadowmin'] = $entry->getValue($this->_params['shadowmin']);
  115. }
  116. // Check if we may change the password.
  117. if ($lookupshadow['shadowlastchange'] &&
  118. $lookupshadow['shadowmin'] &&
  119. ($lookupshadow['shadowlastchange'] + $lookupshadow['shadowmin'] > (time() / 86400))) {
  120. throw new Passwd_Exception(_("Minimum password age has not yet expired"));
  121. }
  122. // Change the user's password and update lastchange.
  123. try {
  124. $entry->replace(array($this->_params['attribute'] => $this->encryptPassword($new_password)), true);
  125. if (!empty($this->_params['shadowlastchange']) &&
  126. $lookupshadow['shadowlastchange']) {
  127. $entry->replace(array($this->_params['shadowlastchange'] => floor(time() / 86400)));
  128. }
  129. $entry->update();
  130. } catch (Horde_Ldap_Exception $e) {
  131. throw new Passwd_Exception($e);
  132. }
  133. }
  134. }