--- ../ldapgroups.module 2009-09-15 12:00:50.000000000 +0100 +++ ldapgroups.module 2009-09-15 11:43:45.000000000 +0100 @@ -62,6 +63,9 @@ function ldapgroups_user($op, &$edit, &$ case 'login': ldapgroups_user_login($account); break; + case 'update': + ldapgroups_user_update($account, $edit); + break; } } @@ -69,6 +73,57 @@ function ldapgroups_user($op, &$edit, &$ // hook_user() functions /** + * Implements hook_user() update operation. + */ +function ldapgroups_user_update(&$account, &$edit) { + // @todo: Possibly also check that role -> group sync is enabled + if (isset($edit['roles']) && is_array($edit['roles'])) { + // Desired roles are established + $authmap = user_get_authmaps($account->name); + if (!isset($authmap['ldapauth'])) { + // This user is not authenticated via lapauth. + return; + } + + // Setup the global $_ldapgroups_ldap object. + if (!_ldapgroups_ldap_init($account)) + return; + + // First, we figure out which groups the user belongs to + $groups = _ldapgroups_detect_groups($account); + // Then filter according to site wide config + $groups = _ldapgroups_filter($account, $groups); + + // Clear user's group membership from LDAP + if ($groups != FALSE) { + _ldapgroups_edit_groups('revoke', $groups, &$account); + } + + // Map roles to groups in order to pass to edit function + $roles = array(); + foreach (array_keys($edit['roles']) as $rid) { + if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { + $result = db_query("SELECT * FROM {role} WHERE rid = '%s'", $rid); + if ($row = db_fetch_object($result)) { + $roles[] = $row->name; + } + } + } + + $groups_grant = array(); + foreach ($roles as $role) { + $group = _ldapgroups_mapping_reverse($user, $role); + if (isset($group)) { + $groups_grant[] = $group; + } + } + + // Grant membership of groups given by assigned roles + _ldapgroups_edit_groups('grant', $groups_grant, &$account); + } +} + +/** * Implements hook_user() login operation. */ function ldapgroups_user_login(&$account) { @@ -127,6 +181,104 @@ function ldapgroups_user_login(&$account // Auxiliary functions /** + * Modify user groups in LDAP. + * + * @param $op + * Operation to perform, either 'revoke' or 'grant' + * @param $groups + * Array of groups to act on. + * @param $user + * A user object. + */ +function _ldapgroups_edit_groups($op, $groups = array(), $user) { + global $_ldapgroups_ldap; + + // Nothing to do if the user is not LDAP authentified + // or there are no groups configured. + if (!(_ldapgroups_ldap_info($user, 'ldapgroups_in_dn') || _ldapgroups_ldap_info($user, 'ldapgroups_in_attr') || _ldapgroups_ldap_info($user, 'ldapgroups_as_entries'))) + return FALSE; + + // Connect using privilaged bind user + $bind_info = _ldapdata_edition($user); + if (!$_ldapgroups_ldap->connect($bind_info['dn'], $bind_info['pass'])) { + watchdog('ldapgroups', "User update: user %name's groups could not be updated in the LDAP directory", array('%name' => $user->name), WATCHDOG_NOTICE); + return; + } + + // Stating with just strategy 3 (groups as entries) since this is what we use + // @todo: extend to other strategies + + // Strategy 1: group extracted from user's DN. + if (_ldapgroups_ldap_info($user, 'ldapgroups_in_dn')) { + switch ($op) { + case 'grant': + + break; + case 'revoke': + + break; + } + } + + // Strategy 2: groups in user attributes. + if (_ldapgroups_ldap_info($user, 'ldapgroups_in_attr')) { + switch ($op) { + case 'grant': + + break; + case 'revoke': + + break; + } + } + + // Strategy 3: groups as entries. + $ldapgroups_entries_attribute = _ldapgroups_ldap_info($user, 'ldapgroups_entries_attribute'); + if (_ldapgroups_ldap_info($user, 'ldapgroups_as_entries')) { + switch ($op) { + case 'grant': + foreach ($groups as $group) { + $members = $_ldapgroups_ldap->retrieveMultiAttribute($group, $ldapgroups_entries_attribute); + $members[] = $user->name; + $_ldapgroups_ldap->writeAttributes($group, array($ldapgroups_entries_attribute => $members)); + } + break; + case 'revoke': + foreach ($groups as $group) { + $members = $_ldapgroups_ldap->retrieveMultiAttribute($group, $ldapgroups_entries_attribute); + $members = array_values(array_diff($members, array($user->name))); + $_ldapgroups_ldap->writeAttributes($group, array($ldapgroups_entries_attribute => $members)); + } + break; + } + } + + $_ldapgroups_ldap->disconnect(); +} + +/** + * Retrieve LDAP write credentials. + * + * @param $sid + * A server ID or user object. + * + * @return + * An array with the LDAP write username and password. + */ +function _ldapgroups_edition($sid) { + if (!($sid = is_object($sid) ? (isset($sid->ldap_config) ? $sid->ldap_config : NULL) : $sid)) + return; + + // @fixme: This currently relies on ldapdata. There should be a way to remove this dependency without recreating too much code. + $row = db_fetch_object(db_query("SELECT ldapdata_binddn, ldapdata_bindpw FROM {ldapauth} WHERE sid = %d", $sid)); + + return array( + 'dn' => $row->ldapdata_binddn ? $row->ldapdata_binddn : (isset($_SESSION['ldap_login']['dn']) ? $_SESSION['ldap_login']['dn'] : ''), + 'pass' => $row->ldapdata_bindpw ? $row->ldapdata_bindpw : (isset($_SESSION['ldap_login']['pass']) ? $_SESSION['ldap_login']['pass'] : ''), + ); +} + +/** * Detect user groups from the LDAP. * * @param $user @@ -301,6 +453,41 @@ function _ldapgroups_mapping($user, $gro } /** + * Maps Drupal role name to LDAP group name. + * + * @param $user + * A user object. + * @param $role + * A Drupal role name. + * + * @return + * An LDAP group. + */ +function _ldapgroups_mapping_reverse($user, $role) { + // @todo: Write reverse mapping function + // @fixme: This chunk of code has various problems. + // Number 1: the mappings dont appear to be pulled from the info function + // Number 2: the preg_match() is pointless since we're trying to add to a string, not extract from it + // Number 3: Manual mapping is required in order to add the correct root DN to a group + + /* + $ldapgroups_mappings = _ldapgroups_ldap_info($user, 'ldapgroups_mappings_filter'); + print_r($ldapgroups_mappings); + if (is_array($ldapgroups_mappings)) { + $ldapgroups_mappings_reverse = array_flip($ldapgroups_mappings); + } + if (isset($ldapgroups_mappings_reverse[$role])) + return $ldapgroups_mappings_reverse[$role]; + else if (preg_match('/^[^=]+=([^,]+),.*$/', $role, $matches)) + return $matches[1]; + else + return NULL; + */ + $role = "cn=" . $role . ",ou=Fuse,dc=studio,dc=fusefm,dc=co,dc=uk"; + return $role; +} + +/** * Initiates the LDAPInterfase class. * * @param $sid