示例#1
0
	/**
	 * Method is called before user data is stored in the database.
	 *
	 * Changes the password in LDAP if the user changed their password.
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isNew  True if a new user is stored.
	 * @param   array    $new    Holds the new user data.
	 *
	 * @return  boolean  Cancels the save if False.
	 *
	 * @since   2.0
	 */
	public function onUserBeforeSave($user, $isNew, $new)
	{
		if ($isNew)
		{
			// We dont want to deal with new users here
			return;
		}

		// Get username and password to use for authenticating with Ldap
		$username 	= SHUtilArrayhelper::getValue($user, 'username', false, 'string');
		$password 	= SHUtilArrayhelper::getValue($new, 'password_clear', null, 'string');

		if (!empty($password))
		{
			$auth = array(
				'authenticate' => SHLdap::AUTH_USER,
				'username' => $username,
				'password' => $password
			);

			try
			{
				// We will double check the password for double safety (breaks password reset if on)
				$authenticate = $this->params->get('authenticate', 0);

				// Get the user adapter then set the password on it
				$adapter = SHFactory::getUserAdapter($auth);

				$adapter->setPassword(
					$password,
					SHUtilArrayhelper::getValue($new, 'current-password', null, 'string'),
					$authenticate
				);

				SHLog::add(JText::sprintf('PLG_LDAP_PASSWORD_INFO_12411', $username), 12411, JLog::INFO, 'ldap');
			}
			catch (Exception $e)
			{
				// Log and Error out
				SHLog::add($e, 12401, JLog::ERROR, 'ldap');

				return false;
			}
		}
	}
示例#2
0
	/**
	 * Create the user to LDAP (before onUserBeforeSave).
	 *
	 * @param   array  $user  Populated LDAP attributes from the form.
	 *
	 * @return  boolean  Cancels the user creation to Joomla if False.
	 *
	 * @since   2.0
	 */
	public function onUserCreation($user)
	{
		try
		{
			$dn = null;
			$attributes = array();

			// Populate defaults for the mandatory
			$mandatory = array(
				'username' => SHUtilArrayhelper::getValue($user, 'username'),
				'password' => SHUtilArrayhelper::getValue($user, 'password_clear'),
				'email' => SHUtilArrayhelper::getValue($user, 'email'),
				'name' => SHUtilArrayhelper::getValue($user, 'name')
			);

			// Include the helper file only if it exists
			if ($this->helper = $this->_getHelperFile())
			{
				// Calculate the correct domain to insert user on
				if (method_exists($this->helper, 'getDomain'))
				{
					$this->domain = $this->helper->getDomain($user);
				}
			}

			$fields = $this->_getXMLFields();

			// Loops around everything in the template XML
			foreach ($fields as $key => $value)
			{
				// Convert the value to a string
				$stringValue = (string) $value;

				// Convert the key to a string
				$stringKey = (string) $key;

				$name = (string) $value->attributes()->name;

				if ($stringKey == 'dn')
				{
					$name = 'mandatory' . $stringKey;

					// The dn which isn't an array
					$attribute =& $dn;
				}
				elseif ($stringKey == 'username' || $stringKey == 'password' || $stringKey == 'email' || $stringKey == 'name')
				{
					$name = 'mandatory' . $stringKey;

					// The mandatory fields use something a bit different
					$attribute =& $mandatory[$stringKey];
				}
				else
				{
					// Standard multi-array attributes
					if (!isset($attributes[$name]))
					{
						$attributes[$name] = array();
					}

					$attribute =& $attributes[$name][];
				}

				// Get the value of the attributes using a variety of types
				switch ((string) $value->attributes()->type)
				{
					case 'form':
						$attribute = $user[$stringValue];
						break;

					case 'string':
						$attribute = $stringValue;
						break;

					case 'eval':
						$attribute = $this->_execEval($stringValue, $user);
						break;

					case 'helper':
						$method = 'get' . (string) $name;
						$attribute = $this->helper->{$method}($user);
						break;
				}
			}

			$credentials = array(
				'username' => $mandatory['username'],
				'password' => $mandatory['password'],
				'domain' => $this->domain,
				'dn' => $dn
			);

			// Kill any previous adapters for this user (though this plugin should be ordered first!!)
			SHFactory::$adapters[strtolower($user['username'])] = null;

			// Create an adapter and save core attributes
			$adapter = SHFactory::getUserAdapter($credentials, 'ldap', array('isNew' => true));

			// Add core Joomla fields
			$adapter->setAttributes(
				array(
					'username' => $mandatory['username'],
					'password' => $mandatory['password'],
					'fullname' => $mandatory['name'],
					'email' => $mandatory['email']
				)
			);

			// Add extra fields based from the template xml
			$adapter->setAttributes($attributes);

			// Create the LDAP user now
			SHLdapHelper::commitChanges($adapter, true, true);
			SHLog::add(JText::sprintf('PLG_LDAP_CREATION_INFO_12821', $mandatory['username']), 12821, JLog::INFO, 'ldap');

			$this->username = $mandatory['username'];

			/*
			 * Call onAfterCreation method in the helper which can be used to run
			 * external scripts (such as creating home directories) and/or adding
			 * groups to the new user.
			 *
			 * This method will be passed:
			 * - $user        Values directly from the user registration form.
			 * - $attributes  The attributes passed to the LDAP server for creation.
			 * - $adapter     The user adapter object.
			 */
			if ($this->helper && method_exists($this->helper, 'onAfterCreation'))
			{
				$this->helper->onAfterCreation($user, $attributes, $adapter);
			}

			return true;
		}
		catch (Exception $e)
		{
			SHLog::add($e, 12802, JLog::ERROR, 'ldap');

			return false;
		}
	}
示例#3
0
	/**
	 * Method is called on user login failure.
	 *
	 * @param   array  $response  The authentication response.
	 *
	 * @return  void
	 *
	 * @since   2.0
	 */
	public function onUserLoginFailure($response)
	{
		// Check if the attempted login was an Ldap user, if so then fire the event
		if ($username = SHUtilArrayhelper::getValue($response, 'username', false, 'string'))
		{
			// Check if the user exists in the J! database
			if ($id = JUserHelper::getUserId($username))
			{
				if (SHLdapHelper::isUserLdap($id))
				{
					SHLdapHelper::triggerEvent('onUserLoginFailure', array($response));
				}
			}
		}
	}
示例#4
0
	/**
	 * Method is called before user data is stored in the database.
	 *
	 * Saves profile data to LDAP if a profile form is detected.
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isNew  True if a new user is stored.
	 * @param   array    $new    Holds the new user data.
	 *
	 * @return  boolean  Cancels the save if False.
	 *
	 * @since   2.0
	 */
	public function onUserBeforeSave($user, $isNew, $new)
	{
		if (!$this->params->get('allow_ldap_save', 1))
		{
			// Not allowed to save back to LDAP
			return;
		}

		// Default the return result to true
		$result = true;

		try
		{
			// Get username for adapter
			$username = SHUtilArrayhelper::getValue($user, 'username', false, 'string');

			if (empty($username))
			{
				// The old username isn't present so use new username
				$username = SHUtilArrayhelper::getValue($new, 'username', false, 'string');
			}

			// Include the mandatory Joomla fields (fullname and email)
			$this->saveMandatoryToLdap($username, $new['name'], $new['email']);

			// Check there is a profile to save (i.e. this event may not have been called from the profile form)
			if ($this->use_profile && (isset($new[self::FORM_FIELDS_NAME]) && (count($new[self::FORM_FIELDS_NAME]))))
			{
				$xml = $this->getXMLFields(SHUserHelper::getDomainParam($new));

				// Only get profile data and enabled elements from the input
				$profileData = $this->cleanInput($xml, $new[self::FORM_FIELDS_NAME]);

				// Save the profile back to LDAP
				$result = $this->saveProfileToLdap($xml, $username, $profileData);
			}
		}
		catch (Exception $e)
		{
			SHLog::add($e, 12232, JLog::ERROR, 'ldap');

			return false;
		}

		return $result;
	}
示例#5
0
	/**
	 * Find the correct Ldap parameters based on the authorised and configuration
	 * specified. If found then return the successful Ldap object.
	 *
	 * Note: you can use SHLdap::lastUserDn for the user DN instead of rechecking again.
	 *
	 * @param   integer|string  $id          Optional configuration record ID.
	 * @param   Array           $authorised  Optional authorisation/authentication options (authenticate, username, password).
	 * @param   JRegistry       $registry    Optional override for platform configuration registry.
	 *
	 * @return  SHLdap  An Ldap object on successful authorisation or False on error.
	 *
	 * @since   2.0
	 * @throws  InvalidArgumentException  Invalid configurations
	 * @throws  SHExceptionStacked        User or configuration issues (may not be important)
	 */
	public static function getInstance($id = null, array $authorised = array(), JRegistry $registry = null)
	{
		// Get the platform registry config from the factory if required
		$registry = is_null($registry) ? SHFactory::getConfig() : $registry;

		// Get the optional authentication/authorisation options
		$authenticate = SHUtilArrayhelper::getValue($authorised, 'authenticate', self::AUTH_NONE);
		$username = SHUtilArrayhelper::getValue($authorised, 'username', null);
		$password = SHUtilArrayhelper::getValue($authorised, 'password', null);

		// Get all the Ldap configs that are enabled and available
		$configs = SHLdapHelper::getConfig($id, $registry);

		// Check if only one configuration result was found
		if ($configs instanceof JRegistry)
		{
			// Wrap this around an array so we can use the same code below
			$configs = array($configs);
		}

		// Keep a record of any exceptions called and only log them after
		$errors = array();

		// Loop around each of the Ldap configs until one authenticates
		foreach ($configs as $config)
		{
			try
			{
				// Get a new SHLdap object
				$ldap = new SHLdap($config);

				// Check if the authenticate/authentication is successful
				if ($ldap->authenticate($authenticate, $username, $password))
				{
					// This is the correct configuration so return the new client
					return $ldap;
				}
			}
			catch (Exception $e)
			{
				// Add the error to the stack
				$errors[] = $e;
			}

			unset($ldap);
		}

		// Failed to find any configs to match
		if (count($errors) > 1)
		{
			// More than one config caused issues, use the stacked exception
			throw new SHExceptionStacked(JText::_('LIB_SHLDAP_ERR_10411'), 10411, $errors);
		}
		else
		{
			// Just rethrow the one exception
			throw $errors[0];
		}
	}
示例#6
0
	/**
	 * Returns the string value of the specified value ID.
	 *
	 * @param   integer  $entry      Entry ID.
	 * @param   string   $attribute  Attribute name.
	 * @param   integer  $value      Value ID.
	 * @param   mixed    $default    Default value to return.
	 *
	 * @return  string   Value or Default
	 *
	 * @since   1.0
	 */
	public function getValue($entry, $attribute, $value, $default = false)
	{
		if (($getAttribute = $this->getAttribute($entry, $attribute, false)) === false)
		{
			// No such attribute exists
			return $default;
		}

		return SHUtilArrayhelper::getValue($getAttribute, $value, $default);
	}
示例#7
0
	/**
	 * Setups the JCrypt object with default keys if not specified then returns it.
	 *
	 * @param   array  $options  Optional override options for keys.
	 *
	 * @return  JCrypt  The configured JCrypt object.
	 *
	 * @since   2.0
	 */
	public static function getCrypt($options = array())
	{
		$source = strtolower(SHUtilArrayhelper::getValue($options, 'source', 'jconfig', 'string'));

		if ($source === 'jconfig')
		{
			/*
			 * If JConfig has been included then lets check whether the keys
			 * have been imported and if not then use the secret value for now.
			 */
			if (class_exists('JConfig'))
			{
				$config = new JConfig;

				if (!isset($options['key']))
				{
					$options['key'] = $config->secret;
				}
			}
		}
		elseif ($source === 'file')
		{
			$file = SHUtilArrayhelper::getValue($options, 'file', '', 'string');

			if (file_exists($file))
			{
				$options['key'] = file_get_contents($file);
			}
		}

		$crypt = new JCrypt;

		// Create some default options
		$type = SHUtilArrayhelper::getValue($options, 'type', 'simple', 'string');
		$key = SHUtilArrayhelper::getValue($options, 'key', 'DEFAULTKEY', 'string');

		$crypt->setKey(
			new JCryptKey(
				$type,
				$key,
				$key
			)
		);

		return $crypt;
	}
示例#8
0
	/**
	 * Set changes to the attributes within an Ldap distinguished name object.
	 * This method compares the current attribute values against a new changed
	 * set of attribute values and commits the differences.
	 *
	 * @param   array  $options  Optional array of options.
	 *
	 * @return  SHAdapterResponseCommits  Stores all commit objects and status.
	 *
	 * @since   2.0
	 * @throws  RuntimeException
	 */
	public function commitChanges($options = array())
	{
		if ($this->_dn instanceof Exception)
		{
			// Do not retry. Ldap configuration or user has problems.
			throw $this->_dn;
		}

		$response = new SHAdapterResponseCommits;

		if ($this->isNew)
		{
			$options['nothrow'] = true;

			// We only want to create the user
			$response->commits = array($this->create($options));

			return $response;
		}

		if (empty($this->_changes))
		{
			// There is nothing to commit
			return $response;
		}

		// If the user write is enabled then we should just try to authenticate now
		if ($userWrite = SHUtilArrayhelper::getValue($options, 'userWrite', false, 'boolean'))
		{
			$this->getId(true);
		}

		// Get the current attributes
		$current = $this->getAttributes(array_keys($this->_changes), false);

		$deleteEntries 		= array();
		$addEntries 		= array();
		$replaceEntries		= array();

		// Loop around all changes
		foreach ($this->_changes as $key => $value)
		{
			if ($key === 'dn')
			{
				continue;
			}

			$return = 0;

			// Check this attribute for multiple values
			if (is_array($value))
			{
				/* This is a multiple value attriute and to preserve
				 * order we must replace the whole thing if changes
				 * are required.
				 */
				$modification = false;
				$new = array();
				$count = 0;

				for ($i = 0; $i < count($value); ++$i)
				{
					if ($return = self::_checkFieldHelper($current, $key, $count, $value[$i]))
					{
						$modification = true;
					}

					if ($return !== 3 && $value[$i])
					{
						// We don't want to save deletes
						$new[] = $value[$i];
						++$count;
					}
				}

				if ($modification)
				{
					// We want to delete it first
					$deleteEntries[$key] = array();

					if (count($new))
					{
						// Now lets re-add them
						$addEntries[$key] = $new;
					}
				}
			}
			else
			{
				/* This is a single value attribute and we now need to
				 * determine if this needs to be ignored, added,
				 * modified or deleted.
				 */
				$return = self::_checkFieldHelper($current, $key, 0, $value);

				// Check if this is a password attribute as the replace needs to be forced
				if ($key === $this->getPassword(true))
				{
					$replaceEntries[$key] = array($value);
				}
				else
				{
					switch ($return)
					{
						case 1:
							$replaceEntries[$key] = array($value);
							break;

						case 2:
							$addEntries[$key] = array($value);
							break;

						case 3:
							$deleteEntries[$key] = array();
							break;
					}
				}
			}
		}

		// We can now commit the changes to the LDAP server for this DN (order MATTERS!).
		$operations	= array('delete' => $deleteEntries, 'add' => $addEntries, 'replace' => $replaceEntries);

		// Check whether we need to be binded as proxy to write to ldap
		if (!$userWrite && $this->client->bindStatus !== SHLdap::AUTH_PROXY)
		{
			if (!$this->client->proxyBind())
			{
				// Failed to map as a proxy user
				throw new RuntimeException(JText::_('LIB_SHUSERADAPTERSLDAP_ERR_10901'), 10901);
			}
		}

		if (isset($this->_changes['dn']) && ($this->_changes['dn'] != $this->_dn))
		{
			// TODO: Need to rename the DN using SHLdap::rename()
			throw new InvalidArgumentException(JText::_('LIB_SHUSERADAPTERSLDAP_ERR_10922'), 10922);
		}

		foreach ($operations as $operation => $commit)
		{
			// Remove password from this commit
			unset ($commit[$this->getPassword(true)]);

			$method = "{$operation}Attributes";

			// Check there are some attributes to process for this commit
			if (count($commit))
			{
				try
				{
					// Commit the Ldap attribute operation
					$this->client->$method($this->_dn, $commit);

					// Successful commit so say so
					$response->addCommit(
						$operation,
						JText::sprintf(
							'LIB_SHUSERADAPTERSLDAP_INFO_10924',
							$operation,
							$this->username,
							preg_replace('/\s+/', ' ', var_export($commit, true))
						)
					);

					// Change the attribute field for this commit
					$this->_attributes = array_merge($this->_attributes, $commit);

					if ($operation == 'add')
					{
						// Add operation means we need to remove attribute keys from nullAttributes
						foreach (array_keys($commit) as $k)
						{
							if (($index = array_search($k, $this->_nullAttributes)) !== false)
							{
								unset ($this->_nullAttributes[$index]);
							}
						}
					}
					elseif ($operation == 'delete')
					{
						// Delete operation means we need to add attribute keys to nullAttributes
						foreach (array_keys($commit) as $k)
						{
							if (array_search($k, $this->_nullAttributes) === false)
							{
								$this->_nullAttributes[] = $k;
							}
						}
					}
				}
				catch (Exception $e)
				{
					// An error happened trying to commit the change so lets log it
					$response->addCommit(
						$operation,
						JText::sprintf(
							'LIB_SHUSERADAPTERSLDAP_INFO_10926',
							$operation,
							$this->username,
							preg_replace('/\s+/', ' ', var_export($commit, true))
						),
						JLog::ERROR,
						$e
					);
				}
			}
		}

		// Clear the changes even if they failed
		$this->_changes = array();

		return $response;
	}
示例#9
0
	/**
	 * This method handles the user adapter authentication and reports
	 * back to the subject.
	 *
	 * @param   array   $credentials  Array holding the user credentials
	 * @param   array   $options      Array of extra options
	 * @param   object  &$response    Authentication response object
	 *
	 * @return  boolean  Authentication result
	 *
	 * @since   2.0
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		$response->type = self::AUTH_TYPE;

		if (empty($credentials['password']))
		{
			// Blank passwords not allowed to prevent anonymous binding
			$response->status = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('PLG_AUTHENTICATION_SHADAPTER_ERR_12602');

			return;
		}

		// Check the Shmanic platform has been imported
		if (!$this->_checkPlatform())
		{
			// Failed to import the platform
			$response->status = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('PLG_AUTHENTICATION_SHADAPTER_ERR_12601');

			return false;
		}

		// Check if a Domain is present which represents a configuration ID
		if ($domain = SHUtilArrayhelper::getValue($options, 'domain', null, 'cmd'))
		{
			// Valid configuration ID (normally for SSO)
			$credentials['domain'] = $domain;
		}
		else
		{
			// See if we can get the domain directly from the input
			if ($domain = JFactory::getApplication()->input->get('login_domain', null, 'cmd'))
			{
				$credentials['domain'] = $domain;
			}
		}

		/*
		 * Attempt to authenticate with user adapter. This method will automatically detect
		 * the correct configuration (if multiple ones are specified) and return a
		 * SHUserAdapter* object. If the getid returns empty or it throws an error then
		 * authentication was unsuccessful.
		 */
		try
		{
			// Setup new user adapter
			$adapter = SHFactory::getUserAdapter($credentials);

			// Get the authenticating user dn
			$id = $adapter->getId(true);

			// Get the required attributes (this gets core attributes + plugin based)
			if (!empty($id) && $attributes = $adapter->getAttributes())
			{
				// Report back with success
				$response->status			= JAuthentication::STATUS_SUCCESS;
				$response->error_message 	= '';

				return true;
			}

			// Unable to find user or attributes missing (an error should get thrown already)
			throw new Exception(JText::_('JGLOBAL_AUTH_NO_USER'), 999);
		}
		catch (Exception $e)
		{
			// Configuration or authentication failure
			$response->status = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('JGLOBAL_AUTH_NO_USER');

			// Process a error log even if it could be a simple incorrect user
			SHLog::add($e, 12621, JLog::ERROR, 'auth');

			return;
		}
	}