public static function setUser(SHUserAdapter $adapter, $JUser) { if (is_numeric($JUser)) { $id = $JUser; } elseif ($JUser instanceof JUser) { $id = $JUser->id; } else { //TODO: lang string throw new RuntimeException('Invalid User ID', 101); } $link = null; // Check if we can retrieve link from cache if (isset(self::$userCache[$adapter->loginuser]) && is_array(self::$userCache[$adapter->loginuser])) { foreach (self::$userCache[$adapter->loginuser] as $links) { if ($links['joomla_id'] === $id) { $link = self::$userCache[$adapter->loginuser]; break; } } } if (empty($link)) { $link = self::lookupFromJoomlaId(self::TYPE_USER, $id); } if ($link) { // Check if we actually need to update if ($link[0]['adapter'] == $adapter->getName() && $link[0]['domain'] == $adapter->getDomain() && $link[0]['username'] == $adapter->getId(false) && $link[0]['joomla_id'] == $id) { return; } // Commit the link update self::update($link[0]['id'], $adapter->getName(), $adapter->getDomain(), $adapter->getId(false), $id); } else { // Commit the link insert self::insert(self::TYPE_USER, $adapter->getName(), $adapter->getDomain(), $adapter->getId(false), $id); } unset(self::$userCache['U_' . $adapter->loginuser]); unset(self::$userCache['I_' . $id]); }
/** * Save the users profile to the database. * * @param integer $userId Joomla user ID to save. * @param string $username Joomla username to save. * @param SHUserAdapter $adapter User adapter of LDAP user. * @param array $options An optional set of options. * * @return boolean True on success * * @since 2.0 */ protected function saveProfile($userId, $username, $adapter, $options = array()) { $xml = $this->getXMLFields($adapter->getDomain()); SHLog::add(JText::sprintf('PLG_LDAP_PROFILE_DEBUG_12221', $username), 12221, JLog::DEBUG, 'ldap'); $addRecords = array(); $updateRecords = array(); $deleteRecords = array(); $db = JFactory::getDBO(); $query = $db->getQuery(true); // Lets get a list of current SQL entries if (is_null($current = $this->queryProfile($userId, true))) { return false; } /* We want to process each attribute in the XML * then find out if it exists in the LDAP directory. * If it does, then we compare that to the value * currently in the SQL database. */ $attributes = $this->getAttributes($xml); foreach ($attributes as $attribute) { // Lets check for a delimiter (this is the indicator that multiple values are supported) $delimiter = null; $xmlField = $xml->xpath("fieldset/field[@name='$attribute']"); $value = null; if ($delimiter = (string) $xmlField[0]['delimiter']) { // These are potentially multiple values if (strToUpper($delimiter) == 'NEWLINE') { $delimiter = "\n"; } $value = ''; if ($v = $adapter->getAttributes($attribute)) { if (is_array($v[$attribute])) { foreach ($v[$attribute] as $values) { $value .= $values . $delimiter; } } } } else { // These are single values if ($v = $adapter->getAttributes($attribute)) { if (isset($v[$attribute][0])) { $value = $v[$attribute][0]; } } } // Get the action status required against the SQL table $status = $this->checkSqlField($current, $attribute, $value); switch ($status) { case 1: $updateRecords[$attribute] = $value; break; case 2: $addRecords[$attribute] = $value; break; case 3: $deleteRecords[] = $attribute; break; } } /* Lets commit these differences to the database * in steps (delete, add, update) and return the * result. */ $results = array(); if (count($deleteRecords)) { $results[] = $this->deleteRecords($userId, $deleteRecords); } if (count($addRecords)) { $results[] = $this->addRecords($userId, $addRecords, count($current) + 1); } if (count($updateRecords)) { $results[] = $this->updateRecords($userId, $updateRecords); } $return = (!in_array(false, $results, true)); if (count($results)) { // Changes occurred so lets log it SHLog::add( JText::sprintf( 'PLG_LDAP_PROFILE_DEBUG_12225', $username, $return == 1 ? JText::_('PLG_LDAP_PROFILE_SUCCESS') : JText::_('PLG_LDAP_PROFILE_FAIL') ), 12225, JLog::DEBUG, 'ldap' ); if (!$return) { // There was an error return false; } // Everything went well - we have updated both LDAP and the J! database. SHLog::add(JText::sprintf('PLG_LDAP_PROFILE_INFO_12224', $username), 12224, JLog::INFO, 'ldap'); // Return this was successful and something was updated return true; } else { // No changes occurred so log that the profile was up to date SHLog::add( JText::sprintf('PLG_LDAP_PROFILE_DEBUG_12226', $username), 12226, JLog::DEBUG, 'ldap' ); return; } }
/** * Called after a user LDAP read to gather extra ldap attribute values that * were not included in the initial read. * * @param SHUserAdapter $adapter The current user adapter. * @param array &$attributes Discovered User Ldap attribute keys=>values. * @param array $options Array holding options. * * @return void * * @since 2.0 */ public function onLdapAfterRead($adapter, &$attributes, $options = array()) { if (!$this->doSetup()) { return; } $details = array(); $return = array(); $groups = array(); /* Firstly, we need to check if there are any initial groups discovered * if a forward lookup is being used. If not then we need to find these * initial groups first. */ if ($this->lookup_type === self::LOOKUP_FORWARD) { /* * Attempt to do a forward lookup if the Ldap user group attributes are * not present. Though in most cases, they should be present. */ if (!isset($attributes[$this->memberof_attribute])) { // We cannot get any more information if there is no source user DN if (is_null($adapter->getId(false))) { return false; } // Add to the user attribute request for an Ldap read $details[] = $this->memberof_attribute; $return = $details; } else { if (!count($attributes[$this->memberof_attribute])) { // There are no groups to process for this user (or the parameter was set incorrectly) return true; } // Yes we have groups already, we just need to check for recursion if required laters $groups = $attributes[$this->memberof_attribute]; } } else { // Attempt to do a reverse lookup $return[] = $this->member_attribute; // The following will only execute if the attributes doesnt have what is required for reverse lookup if (!isset($attributes[$this->member_dn]) || is_null($this->member_dn)) { // We cannot get any more information if there is no source user DN if (is_null($adapter->getId(false))) { return false; } // This will indicate another ldap read later $details[] = $this->member_dn; } } // Lets get our result ready $return = array_fill_keys($return, null); $result = null; if (count($details)) { // Get our ldap user attributes and check we have a valid result $result = $adapter->client->read($adapter->getId(false), null, $details); } if (!count($groups)) { // Need to process first level user groups from the ldap result if ($this->lookup_type === self::LOOKUP_FORWARD) { // Forward lookup: all we need is the user group values $groups = $result->getAttribute(0, $this->memberof_attribute, array()); } else { // Reverse lookup: have to find the groups with the user dn present $lookupValue = is_null($result) ? $attributes[$this->member_dn][0] : $result->getValue(0, $this->member_dn, 0); // Build the search filter for this $search = $this->member_attribute . '=' . $lookupValue; $search = SHLDAPHelper::buildFilter(array($search)); // Find all the groups that have this user present as a member if (($reverse = $adapter->client->search(null, $search, array('dn'))) !== false) { for ($i = 0; $i < $reverse->countEntries(); ++$i) { // Extract the group distinguished name from the result $groups[] = $reverse->getDN($i); } } } } // Need to process the recursion using the initial groups as a basis if ($this->recursion && count($groups)) { // Check if the Adapter is LDAP based if ($adapter::getType('LDAP')) { $outcome = array(); if ($this->lookup_type === self::LOOKUP_REVERSE) { // We need to override the lookup attribute for reverse recursion self::getRecursiveGroups($adapter->client, $groups, $this->recursion_depth, $outcome, 'dn', $this->member_attribute); } else { self::getRecursiveGroups($adapter->client, $groups, $this->recursion_depth, $outcome, $this->memberof_attribute, $this->dn_attribute); } // We need to merge them back together without duplicates $groups = array_unique(array_merge($groups, $outcome)); } } // Lets store the groups $groups = array_values($groups); $attributes[$this->lookup_type === self::LOOKUP_FORWARD ? $this->memberof_attribute : $this->member_attribute] = $groups; return true; }
/** * Returns the domain or the configuration ID used for this specific user. * * @return string Domain or Configuration ID. * * @since 2.0 */ public function getDomain() { if (is_null($this->domain)) { // Lets pull the domain from the SHLdap object $this->getId(false); $this->domain = $this->client->domain; } return parent::getDomain(); }