[dev] improvements on Auth LDAP driver
Amith Varghese
amith at xalan.com
Mon Oct 13 12:40:45 PDT 2003
Here's a patch the enhances the Auth LDAP driver by adding functionality to edit
and remove users. In addition the driver now supports binding to the LDAP tree
using a bind dn and password. Because many LDAP servers are set up differently
the driver can optionally use a hook so that anyone who uses the driver can
customize what attributes they want to use when an object is edited/added to
the directory.
The following files were changed:
hooks.php.dist -> Gives an example of the _horde_hook_authldap hook
conf.php.dist -> turns the hook off by default
ldap.php -> the driver itself
Please let me know if there are any questions.
Amith
-------------- next part --------------
Index: conf.php.dist
===================================================================
RCS file: /repository/horde/config/conf.php.dist,v
retrieving revision 1.62
diff -u -r1.62 conf.php.dist
--- conf.php.dist 30 Sep 2003 22:11:51 -0000 1.62
+++ conf.php.dist 13 Oct 2003 15:11:44 -0000
@@ -525,3 +525,8 @@
// false, authentication will fail.
// There are examples for such functions in horde/config/hooks.php.dist.
$conf['hooks']['postauthenticate'] = false;
+
+// If this is set to true, the function _horde_hook_authldap() will be used
+// to create and set the attributes needed to add/edit/delete users by the
+// LDAP Auth driver
+$conf['hooks']['authldap'] = false;
Index: hooks.php.dist
===================================================================
RCS file: /repository/horde/config/hooks.php.dist,v
retrieving revision 1.49
diff -u -r1.49 hooks.php.dist
--- hooks.php.dist 30 Sep 2003 22:11:51 -0000 1.49
+++ hooks.php.dist 13 Oct 2003 15:12:01 -0000
@@ -256,6 +256,46 @@
}
}
+// Here is an example of creating credentials needed by the LDAP Auth driver for
+// adding/deleting/updating users.
+if (!function_exists('_horde_hook_authldap')) {
+ function _horde_hook_authldap($userID, $credentials = null)
+ {
+ $entry['dn'] = 'uid=' . $userID . ',ou=People,dc=example.com';
+ if (isset($credentials) && isset($credentials['user_fullname'])) {
+ $entry['cn'] = $credentials['user_fullname'];
+ } else {
+ $entry['cn'] = $userID;
+ }
+ $entry['sn'] = $userID;
+ $entry['objectclass'][0] = 'top';
+ $entry['objectclass'][1] = 'person';
+ $entry['objectclass'][2] = 'qmailuser';
+ $entry['objectclass'][3] = 'CourierMailACcount';
+ $entry['mailhost'] = 'mail.example.com';
+ $entry['mailMessageStore'] = '/home/mail/' . $userID;
+ $entry['homeDirectory'] = '/home/mail/' . $userID;
+ $entry['mailbox'] = $entry['homeDirectory'] . '/Maildir';
+ $entry['uid'] = $userID;
+ $entry['accountStatus'] = 'active';
+ $entry['mailQuota'] = '104857600S';
+ $entry['mail'] = $userID;
+ $entry['uidNumber'] = 501;
+ $entry['gidNumber'] = 501;
+
+ // need to check for new users (password) and edited users (user_pass_2)
+ if (isset($credentials) && isset($credentials['password'])) {
+ $entry['userPassword'] = '{MD5}' . base64_encode(mHash(MHASH_MD5, $
+credentials['password']));
+ } else if (isset($credentials) && isset($credentials['user_pass_2'])) {
+ $entry['userPassword'] = '{MD5}' . base64_encode(mHash(MHASH_MD5, $
+credentials['user_pass_2']));
+ }
+ $entry['deliveryMode'] = 'nolocal';
+ return $entry;
+ }
+}
+
// Here is an example fullname hook function to set the fullname from the GECOS
// information in the passwd file.
if (!function_exists('_prefs_hook_fullname')) {
Index: ldap.php
===================================================================
RCS file: /repository/horde/lib/Auth/ldap.php,v
retrieving revision 1.27
diff -u -r1.27 ldap.php
--- ldap.php 24 Sep 2003 17:44:55 -0000 1.27
+++ ldap.php 13 Oct 2003 15:17:33 -0000
@@ -5,9 +5,16 @@
*
* Required parameters:
* ====================
- * 'basedn' -- The base DN for the LDAP server.
- * 'hostspec' -- The hostname of the LDAP server.
- * 'uid' -- The username search key.
+ * 'basedn' -- The base DN for the LDAP server.
+ * 'hostspec' -- The hostname of the LDAP server.
+ * 'uid' -- The username search key.
+ * 'objectclass' -- The objectclass filter used to search for users. Can
+ * be a single objectclass or an array.
+ *
+ * Optional parameters:
+ * ====================
+ * 'binddn' -- The DN used to bind to the LDAP server
+ * 'passwd' -- The password used to bind to the LDAP server
*
*
* $Horde: horde/lib/Auth/ldap.php,v 1.27 2003/09/24 17:44:55 chuck Exp $
@@ -31,8 +38,8 @@
* @var array $capabilities
*/
var $capabilities = array('add' => true,
- 'update' => false,
- 'remove' => false,
+ 'update' => true,
+ 'remove' => true,
'list' => true,
'transparent' => false);
@@ -92,9 +99,24 @@
return false;
}
+ if (isset($this->_params['binddn'])) {
+ $binddn = $this->_params['binddn'];
+ $bind = @ldap_bind($ldap, $binddn, $this->_params['password']);
+ if (!$bind) {
+ $this->_setAuthError(_("Could not bind to LDAP server."));
+ return false;
+ }
+ }
+
/* Search for the user's full DN. */
- $search = @ldap_search($ldap, $this->_params['basedn'],
- $this->_params['uid'] . '=' . $userID, array($this->_params['uid']));
+ $search = @ldap_search($ldap, $this->_params['basedn'],
+ $this->_params['uid'] . '=' . $userID,
+ array($this->_params['uid']));
+ if (!$search) {
+ $this->_setAuthError(_("Could not search the LDAP server."));
+ return false;
+ }
+
$result = @ldap_get_entries($ldap, $search);
if (is_array($result) && (count($result) > 1)) {
$dn = $result[0]['dn'];
@@ -130,21 +152,138 @@
{
$ldap = @ldap_connect($this->_params['hostspec']);
- $binddn = $this->_params['uid'] . '=' . $this->_params['username'] . ',' . $this->_params['basedn'];
- $bind = @ldap_bind($ldap, $binddn, $this->_params['password']);
+ if (isset($this->_params['binddn'])) {
+ $binddn = $this->_params['binddn'];
+ $bind = @ldap_bind($ldap, $binddn, $this->_params['password']);
+ } else {
+ $bind = @ldap_bind($ldap);
+ }
+
+ global $conf;
+ if (!empty($conf['hooks']['authldap'])) {
+ @include HORDE_BASE . '/config/hooks.php';
+ if (function_exists('_horde_hook_authldap')) {
+ $entry = call_user_func('_horde_hook_authldap', $userID, $credentials);
+ $dn = $entry['dn'];
+ // remove the dn entry from the array
+ unset($entry['dn']);
+ }
+ } else {
+ // Try this simple default and hope it works
+ $dn = $this->_params['uid'] . '=' . $userID . ',' . $this->_params['basedn'];
+ $entry['cn'] = $userID;
+ $entry['sn'] = $userID;
+ // password not encrypted?
+ $entry['userpassword'] = $credentials['password'];
+ }
+ $success = @ldap_add($ldap, $dn, $entry);
+
+ if (!$success) {
+ return PEAR::raiseError(_("Auth_ldap: Unable to add user ") . $userID, __FILE__, __LINE__);
+ }
+ return true;
+ }
+
+ /**
+ * Remove a set of authentication credentials.
+ *
+ * @access public
+ *
+ * @param string $userID The userID to add.
+ *
+ * @return mixed True on success or a PEAR_Error object on failure.
+ */
+ function removeUser($userID)
+ {
+ $ldap = @ldap_connect($this->_params['hostspec']);
+
+ if (isset($this->_params['binddn'])) {
+ $binddn = $this->_params['binddn'];
+ $bind = @ldap_bind($ldap, $binddn, $this->_params['password']);
+ } else {
+ $bind = @ldap_bind($ldap);
+ }
- $dn = $this->_params['uid'] . '=' . $userID . ',' . $this->_params['basedn'];
- $entry['objectClass'][0] = 'top';
- $entry['objectClass'][1] = 'person';
- $entry['cn'] = $userID;
- $entry['sn'] = $userID;
- $entry['userpassword'] = $credentials['password'];
- @ldap_add($ldap, $dn, $entry);
+ global $conf;
+ if (!empty($conf['hooks']['authldap'])) {
+ @include HORDE_BASE . '/config/hooks.php';
+ if (function_exists('_horde_hook_authldap')) {
+ $entry = call_user_func('_horde_hook_authldap', $userID);
+ $dn = $entry['dn'];
+ }
+ } else {
+ // Try this simple default and hope it works
+ $dn = $this->_params['uid'] . '=' . $userID . ',' . $this->_params['basedn'];
+ }
+ $success = @ldap_delete($ldap,$dn);
+ if (!$success) {
+ return PEAR::raiseError(_("Auth_ldap: Unable to remove user ") . $userID, __FILE__, __LINE__);
+ }
return true;
}
/**
+ * Update a set of authentication credentials.
+ *
+ * @access public
+ *
+ * @param string $oldID The old userID.
+ * @param string $newID The new userID.
+ * @param array $credentials The new credentials
+ *
+ * @return mixed True on success or a PEAR_Error object on failure.
+ */
+ function updateUser($oldID, $newID, $credentials)
+ {
+ $ldap = @ldap_connect($this->_params['hostspec']);
+
+ if (isset($this->_params['binddn'])) {
+ $binddn = $this->_params['binddn'];
+ $bind = @ldap_bind($ldap, $binddn, $this->_params['password']);
+ } else {
+ $bind = @ldap_bind($ldap);
+ }
+
+ global $conf;
+ if (!empty($conf['hooks']['authldap'])) {
+ @include HORDE_BASE . '/config/hooks.php';
+ if (function_exists('_horde_hook_authldap')) {
+ $entry = call_user_func('_horde_hook_authldap', $oldID);
+ $olddn = $entry['dn'];
+ $entry = call_user_func('_horde_hook_authldap', $newID);
+ $newdn = $entry['dn'];
+ unset($entry['dn']);
+ }
+ } else {
+ // Try this simple default and hope it works
+ $newdn = $this->_params['uid'] . '=' . $newID . ',' . $this->_params['basedn'];
+ $olddn = $this->_params['uid'] . '=' . $oldID . ',' . $this->_params['basedn'];
+ $entry['userpassword'] = $credentials['user_pass_2'];
+ }
+ if ($oldID != $newID) {
+ if (LDAP_OPT_PROTOCOL_VERSION == 3) {
+ ldap_rename($ldap, $olddn, $newdn, $this->_params['basedn'], true);
+
+ $success = ldap_modify($ldap, $newdn, $entry);
+ } else {
+ $success = $this->addUser($newID, $entry);
+ if ($success) {
+ $success = $this->removeUser($oldID);
+ }
+ }
+ } else {
+ $success = ldap_modify($ldap, $newdn, $entry);
+ }
+
+ if (!$success) {
+ return PEAR::raiseError(_("Auth_ldap: Unable to update user ") . $newID, __FILE__, __LINE__);
+ }
+ return true;
+ }
+
+
+ /**
* List Users
*
* @access public
@@ -155,15 +294,28 @@
{
$ldap = @ldap_connect($this->_params['hostspec']);
- $dn = $this->_params['uid'] . '=' . $this->_params['username'] . ',' . $this->_params['basedn'];
- $bind = @ldap_bind($ldap, $dn, $this->_params['password']);
+ if (isset($this->_params['binddn'])) {
+ $dn = $this->_params['binddn'];
+ $bind = @ldap_bind($ldap, $dn, $this->_params['password']);
+ } else {
+ $bind = @ldap_bind($ldap);
+ }
+
+ if (!is_array($this->_params['objectclass'])) {
+ $filter = 'objectclass=' . $this->_params['objectclass'];
+ } else {
+ $filter = '';
+ foreach ($this->_params['objectclass'] as $objectclass) {
+ $filter = '(&' . $filter;
+ $filter .= '(objectclass=' . $objectclass . '))';
+ }
+ }
- $search = ldap_search($ldap, $this->_params['basedn'],
- 'objectClass=person');
+ $search = ldap_search($ldap, $this->_params['basedn'], $filter);
$entries = ldap_get_entries($ldap, $search);
$userlist = array();
for ($i = 0; $i < $entries['count']; $i++) {
- $userlist[$i] = $entries[$i]['cn'][0];
+ $userlist[$i] = $entries[$i][$this->_params['uid']][0];
}
return $userlist;
More information about the dev
mailing list