Exemple #1
0
	/**
	 * Return specified user attributes from LDAP.
	 *
	 * @param   string|array  $input    Optional string or array of attributes to return.
	 * @param   boolean       $null     Include null or non existent values.
	 * @param   boolean       $changes  Use the attribute changes (before change commit).
	 *
	 * @return  mixed  Ldap attribute results.
	 *
	 * @since   2.0
	 * @throws  SHLdapException
	 */
	public function getAttributes($input = null, $null = false, $changes = false)
	{
		if (is_null($this->_dn))
		{
			$this->getId(false);
		}
		elseif ($this->_dn instanceof Exception)
		{
			// Do not retry. Ldap configuration or user has problems.
			throw $this->_dn;
		}

		$needToFind = array();
		$inputFilled = array();

		if (!is_null($input))
		{
			// Have to make sure that unless its null then its in an array
			$input = is_string($input) ? array($input) : $input;

			$inputFilled = array_fill_keys($input, null);

			// This array is what we must find (i.e. not in the cached variable)
			$needToFind = (array_keys(array_diff_key($inputFilled, $this->_attributes)));

			/*
			 * Combines the current cached attributes with the input attributes with null values.
			 * This will stop the input values from being re-queried on another method call even
			 * if they don't exist.
			 */
			$this->_attributes = (array_merge($inputFilled, $this->_attributes));
		}

		/*
		 * We use the "plugin get attributes" method for efficiency purposes. On the
		 * first execution of this method, we attempt to gather Ldap user attributes
		 * that are required from this call in addition to what the Ldap plugins require.
		 *
		 * This means we should only have to call for the user attributes once from Ldap.
		 */
		if ($this->_usePlugins)
		{
			// Only run the sequence once
			$this->_usePlugins = false;

			/*
			 * -- Get the Ldap user attributes via plugins --
			 * This section will get an array of user detail attributes for the user
			 * using Ldap plugins to help with discovery of required Ldap attributes.
			 */
			$extras = SHFactory::getDispatcher('ldap')->trigger(
				'onLdapBeforeRead', array(&$this, array('dn' => $this->_dn, 'source' => __METHOD__))
			);

			// For each of the LDAP plug-ins returned, merge their extra attributes.
			foreach ($extras as $extra)
			{
				$needToFind = array_merge($needToFind, $extra);
			}

			// Add both of the uid and fullname to the set of attributes to get.
			$needToFind[] = $this->client->ldap_fullname;
			$needToFind[] = $this->client->ldap_uid;

			// Check for a fake email
			$fakeEmail = (strpos($this->client->ldap_email, (SHLdap::USERNAME_REPLACE)) !== false) ? true : false;

			// Add the email attribute only if not a fake email is supplied.
			if (!$fakeEmail)
			{
				$needToFind[] = $this->client->ldap_email;
			}

			// Re-order array to ensure an LDAP read is successful and no duplicates exist.
			$needToFind = array_values(array_unique($needToFind));

			// Swap the attribute names to array keys ready for the result
			$filled = array_fill_keys($needToFind, null);

			/*
			 * Combines the current cached attributes with the input attributes with null values.
			 * This will stop the input values from being re-queried on another method call even
			 * if they don't exist.
			 */
			$this->_attributes = (array_merge($filled, $this->_attributes));

			// Get Ldap user attributes
			$result	= $this->client->read($this->_dn, null, $needToFind);

			if ($result->countEntries())
			{
				// Merge the extra attributes to the cache ready for returning
				$this->_attributes = array_replace($this->_attributes, array_intersect_key($result->getEntry(0), $this->_attributes));
			}

			/*
			 * Save any attributes that weren't found in Ldap and then make it unique
			 * so theres no duplicates in the null attributes list.
			 */
			$unreturnedVals = array_diff($needToFind, array_keys($result->getEntry(0, array())));
			$this->_nullAttributes = array_merge(array_diff($unreturnedVals, $this->_nullAttributes), $this->_nullAttributes);

			if ($fakeEmail)
			{
				// Inject the fake email by replacing the username placeholder with the username from ldap
				$email = str_replace(SHLdap::USERNAME_REPLACE, $this->_attributes[$this->client->ldap_uid][0], $this->client->ldap_email);
				$this->_attributes[$this->client->ldap_email] = array($email);

				// As the last instruction from the fakeEmail condition added email to null, lets remove it
				if (($index = array_search($this->client->ldap_email, $this->_nullAttributes)) !== false)
				{
					unset ($this->_nullAttributes[$index]);
				}
			}

			if (SHLdapHelper::triggerEvent(
				'onLdapAfterRead', array(&$this, &$this->_attributes, array('dn' => $this->_dn, 'source' => __METHOD__))
			) === false)
			{
				// Cancelled login due to plug-in
				throw new RuntimeException(JText::_('LIB_SHUSERADAPTERSLDAP_ERR_10912'), 10912);
			}

			// Blank need to find as there isn't anything more need finding
			$needToFind = array();
		}

		// Check if extra attributes are required
		if (count($needToFind))
		{
			$result = $this->client->read($this->_dn, null, $needToFind);

			if ($result->countEntries())
			{
				// Merge the extra attributes to the cache ready for returning
				$this->_attributes = array_replace($this->_attributes, array_intersect_key($result->getEntry(0), $this->_attributes));
			}

			/*
			 * Save any attributes that weren't found in Ldap and then make it unique
			 * so theres no duplicates in the null attributes list.
			 */
			$unreturnedVals = array_diff($needToFind, array_keys($result->getEntry(0, array())));
			$this->_nullAttributes = array_merge(array_diff($unreturnedVals, $this->_nullAttributes), $this->_nullAttributes);
		}
		else
		{
			// If there are no attributes then get them all from LDAP
			if (!count($this->_attributes))
			{
				$this->_attributes = $this->client->read($this->_dn, null)->getEntry(0, array());
			}
		}

		$return = $this->_attributes;

		// Remove null values from the attributes if we dont want them
		if (!$null)
		{
			$return = array_diff_key($this->_attributes, array_flip($this->_nullAttributes));
			$inputFilled = array_diff_key($inputFilled, array_flip($this->_nullAttributes));
		}

		// Include staged changes to the attributes
		$return = $changes ? array_merge($return, $this->_changes) : $return;

		// Returns only the specified inputs unless all attributes are wanted
		return is_null($input) ? $return : array_replace($inputFilled, array_intersect_key($return, $inputFilled));
	}
 public function testSlapdErrorFunctions()
 {
     $config = TestsHelper::getLdapConfig(214);
     $ldap = new SHLdap($config);
     $ldap->connect();
     $ldap->proxyBind();
     try {
         $ldap->read('cn=doesntexist,dc=shmanic,dc=net');
     } catch (Exception $e) {
         if ($code = $ldap->getErrorCode() === 32) {
             if (!$ldap->getErrorMsg() === SHLdap::errorToString($code)) {
                 $this->fail('Incorrect response message');
             }
         }
     }
 }
Exemple #3
0
 /**
  * Get a users Ldap distinguished name with optional bind authentication.
  *
  * @param   boolean  $authenticate  Attempt to authenticate the user (i.e.
  *						bind the user with the password supplied)
  *
  * @return  string  User DN.
  *
  * @since   2.1
  * @throws  InvalidArgumentException  Invalid argument in config related error
  * @throws  SHLdapException           Ldap specific error.
  * @throws  SHExceptionInvaliduser    User invalid error.
  */
 private function _getDn($authenticate = false)
 {
     $replaced = str_replace(SHLdap::USERNAME_REPLACE, $this->username, $this->_userParams['user_query']);
     /*
      * A basic detection check for LDAP filter.
      * (i.e. distinguished names do not start and end with brackets).
      */
     $useSearch = preg_match('/(?<!\\S)[\\(]([\\S]+)[\\)](?!\\S)/', $this->_userParams['user_query']) ? true : false;
     SHLog::add("Attempt to retrieve user distinguished name using '{$replaced}' " . ($useSearch ? ' with search.' : ' with direct bind.'), 102, JLog::DEBUG, 'ldap');
     // Get a array of distinguished names from either the search or direct bind methods.
     $DNs = $useSearch ? $this->_getDnBySearch() : $this->_getDnDirect();
     if (empty($DNs)) {
         /*
          * Cannot find the specified username. We are going to throw
          * a special user not found error to try to split between
          * configuration errors and invalid errors. However, this might
          * still be a configuration error.
          */
         throw new SHExceptionInvaliduser(JText::_('LIB_SHLDAP_ERR_10302'), 10302, $this->username);
     }
     // Check if we have to authenticate the distinguished name with a password
     if ($authenticate) {
         // Attempt to bind each distinguished name with the specified password then return it
         foreach ($DNs as $dn) {
             if ($this->client->bind($dn, $this->password)) {
                 // Successfully binded with this distinguished name
                 SHLog::add("Successfully authenticated {$this->username} with distinguished name {$dn}.", 102, JLog::DEBUG, 'ldap');
                 return $dn;
             }
         }
         if ($useSearch) {
             // User found, but was unable to bind with the supplied password
             throw new SHExceptionInvaliduser(JText::_('LIB_SHLDAP_ERR_10303'), 10303, $this->username);
         } else {
             // Unable to bind directly to the given distinguished name parameters
             throw new SHExceptionInvaliduser(JText::_('LIB_SHLDAP_ERR_10304'), 10304, $this->username);
         }
     } else {
         $result = false;
         if ($useSearch) {
             /* We can be sure the distinguished name(s) exists in the Ldap
              * directory. However, we cannot be sure if the correct
              * distinguished name is returned for the specified user without
              * authenticating. Therefore, we have to assume the first (and
              * hopefully only) distinguished name is correct.
              * If the correct configuration has been given and the Ldap
              * directory is well organised, this will always be correct.
              */
             $result = $DNs[0];
         } else {
             /* Unlike searching, binding directly means we cannot be sure
              * if the distinguished name(s) exists in the Ldap directory.
              * Therefore, lets attempt to bind with a proxy user, then Ldap
              * read each distinguished name's entity to check if it exists.
              * If binding with the proxy user fails, then we have no option
              * but to assume the first distinguished name exists.
              */
             if ($this->client->proxyBind()) {
                 foreach ($DNs as $dn) {
                     try {
                         $read = $this->client->read($dn, null, array('dn'));
                     } catch (Exception $e) {
                         // We don't need to worry about the exception too much
                         SHLog::add("Failed to read direct bind without auth DN {$dn}.", 102, JLog::DEBUG, 'ldap');
                         continue;
                     }
                     // Check if the distinguished name entity exists
                     if ($read->countEntries() > 0) {
                         // It exists so we assume this is the correct distinguished name.
                         $result = $dn;
                         break;
                     }
                 }
                 if ($result === false) {
                     // Failed to find any of the distinguished name(s) in the Ldap directory.
                     throw new SHExceptionInvaliduser(JText::_('LIB_SHLDAP_ERR_10305'), 10305, $this->username);
                 }
             } else {
                 // Unable to check Ldap directory, so have to assume the first is correct
                 $result = $DNs[0];
             }
         }
         SHLog::add("Using distinguished name {$result} for user {$this->username}.", 102, JLog::DEBUG, 'ldap');
         return $result;
     }
 }