/** * Method to get the field input markup. * * @return string The field input markup. * * @since 1.6 */ protected function getInput() { $html = array(); $attr = ''; // Initialize some field attributes. $attr .= $this->element['class'] ? ' class="' . (string) $this->element['class'] . '"' : ''; $attr .= (string) $this->element['disabled'] == 'true' ? ' disabled="disabled"' : ''; $attr .= $this->element['size'] ? ' size="' . (int) $this->element['size'] . '"' : ''; // Initialize JavaScript field attributes. $attr .= $this->element['onchange'] ? ' onchange="' . (string) $this->element['onchange'] . '"' : ''; // Get some field values from the form. $id = (int) $this->form->getValue('id'); $db = JFactory::getDbo(); $table = SHFactory::getConfig()->get('ldap:table', '#__sh_ldap_config'); $query = $db->getQuery(true); // Build the query for the ordering list $query->select('ordering AS value')->select('name AS text')->select($db->quoteName('id'))->from($db->quoteName($table))->order($db->quoteName('ordering')); if ((string) $this->element['readonly'] == 'true') { // Create a read-only list (no name) with a hidden input to store the value. $html[] = JHtml::_('list.ordering', '', (string) $query, trim($attr), $this->value, $id ? 0 : 1); $html[] = '<input type="hidden" name="' . $this->name . '" value="' . $this->value . '"/>'; } else { // Create a regular list. $html[] = JHtml::_('list.ordering', $this->name, (string) $query, trim($attr), $this->value, $id ? 0 : 1); } return implode($html); }
public function setUp() { parent::setUp(); parent::setUpBeforeClass(); $this->saveFactoryState(); SHFactory::$config = null; }
/** * 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 = JArrayHelper::getValue($user, 'username', false, 'string'); $password = JArrayHelper::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, JArrayHelper::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; } } }
public function testConfigInvalidSource() { $this->setExpectedException('InvalidArgumentException', 'LIB_SHLDAPHELPER_ERR_10601', 10601); // Change it to a invalid LDAP config source $platform = SHFactory::getConfig('file', array('file' => static::PLATFORM_CONFIG_FILE, 'namespace' => 'single')); $platform->set('ldap.config', 84); SHLdapHelper::getConfig(null, $platform); }
public function setUp() { // Clear the static config from factory SHFactory::$config = null; SHFactory::$ldap = null; // Create some files TestsHelper::createPlatformConfigFile(1, static::PLATFORM_CONFIG_FILE); TestsHelper::createLdapConfigFile(214, static::LDAP_CONFIG_FILE); parent::setUp(); }
/** * Restores the Factory pointers * * @return void */ protected function restoreFactoryState() { JFactory::$application = $this->savedFactoryState['application']; JFactory::$config = $this->savedFactoryState['config']; JFactory::$session = $this->savedFactoryState['session']; JFactory::$language = $this->savedFactoryState['language']; JFactory::$document = $this->savedFactoryState['document']; JFactory::$acl = $this->savedFactoryState['acl']; JFactory::$database = $this->savedFactoryState['database']; JFactory::$mailer = $this->savedFactoryState['mailer']; SHFactory::$config = $this->savedFactoryState['shconfig']; SHFactory::$dispatcher = $this->savedFactoryState['shdispatcher']; }
/** * Deletes the user from LDAP if the deletion in the Joomla database was successful. * * Method is called after user data is deleted from the database. * * @param array $user Holds the user data. * @param boolean $success True if user was successfully deleted from the database. * @param string $msg An error message. * * @return void * * @since 2.0 * @deprecated */ public function onUserAfterDelete($user, $success, $msg) { if ($success) { try { $username = $user['username']; SHLog::add(JText::sprintf('PLG_LDAP_DELETION_DEBUG_12905', $username), 12905, JLog::DEBUG, 'ldap'); // Pick up the user and delete it using the User Adapter $adapter = SHFactory::getUserAdapter($username); $adapter->delete(); SHLog::add(JText::sprintf('PLG_LDAP_DELETION_INFO_12908', $username), 12908, JLog::INFO, 'ldap'); } catch (Exception $e) { SHLog::add($e, 12901, JLog::ERROR, 'ldap'); } } }
/** * Method to test the ldap password against the current ldap password * * @param SimpleXMLElement &$element The SimpleXMLElement object representing the <field /> tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param JRegistry &$input An optional JRegistry object with the entire data set to validate against the entire form. * @param object &$form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 11.1 * @throws JException on invalid rule. */ public function test(&$element, $value, $group = null, &$input = null, &$form = null) { if ($form instanceof JForm && $form->getValue('id')) { try { // Gets the username from the user id $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->select($db->quoteName('username'))->from($db->quoteName('#__users'))->where($db->quoteName('id') . ' = ' . $db->quote((int) $form->getValue('id'))); $db->setQuery($query)->execute(); if ($username = $db->loadResult()) { // Put username and password together for authenticating with Ldap $auth = array('username' => $username, 'password' => $value); // This is a valid username so lets check it against ldap return SHFactory::getUserAdapter($auth)->getId(true) ? true : false; } } catch (Exception $e) { // We ignore the exception for now return false; } } }
/** * Calls any registered adapter events associated with an event group. * * @param string $dispatch Dispatcher name OR null to dispatch to all. * @param string $event The event name. * @param array $args An array of arguments. * * @return boolean Result of all function calls. * * @since 2.1 */ public static function triggerEvent($dispatch, $event, $args = null) { if (is_null($dispatch)) { $results = array(); // Loop through all dispatchers and trigger the event foreach (SHFactory::$dispatcher as $dispatcher) { array_push($results, $dispatcher->trigger($event, $args)); } } else { // Single dispatcher trigger $results = SHFactory::getDispatcher($dispatch)->trigger($event, $args); } // We want to return the actual result (false, true or blank) if (in_array(false, $results, true)) { return false; } elseif (in_array(true, $results, true)) { return true; } else { return; } }
/** * Initialises and imports the Shmanic platform and project libraries. * This is fired on application initialise typically by the CMS. * * @return void * * @since 2.0 */ public function onAfterInitialise() { // Check if the Shmanic platform has already been imported if (!defined('SHPATH_PLATFORM')) { $platform = JPATH_PLATFORM . '/shmanic/import.php'; if (!file_exists($platform)) { // Failed to find the import file return false; } // Shmanic Platform import if (!(include_once $platform)) { // Failed to import the Shmanic platform return false; } } // Import the logging method SHLog::import($this->params->get('log_group', 'shlog')); // Container to store project specific import results $results = array(); // Use the default SQL configuration $config = SHFactory::getConfig(); // Get all the importable projects if ($imports = json_decode($config->get('platform.import'))) { foreach ($imports as $project) { // Attempts to import the specified project $results[] = shImport(trim($project)); } } // Fire the onAfterInitialise for all the registered imports/projects JDispatcher::getInstance()->trigger('onSHPlaformInitialise'); if (in_array(false, $results, true)) { // One of the specific projects failed to import return false; } // Everything imported successfully return true; }
/** * This method handles the user adapter authorisation and reports * back to the subject. This method is also used for single sign on. * * There is no custom logging in the authentication. * * @param array $response Authentication response object from onUserAuthenticate() * @param array $options Array of extra options * * @return JAuthenticationResponse Authentication response object * * @since 2.0 */ public function onUserAuthorisation($response, $options = array()) { // Create a new authentication response $retResponse = new JAuthenticationResponse(); // Check if some other authentication system is dealing with this request if (!empty($response->type) && strtoupper($response->type) !== self::AUTH_TYPE) { return $retResponse; } // 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; } $response->type = self::AUTH_TYPE; /* * Attempt to authorise with User Adapter. This method will automatically detect * the correct configuration (if multiple ones are specified) and return a * SHUserAdapter object. If this method returns false, then the authorise was * unsuccessful - basically the user was not found or configuration was * bad. */ try { // Setup user adapter injecting the domain from SSO if specified $credentials = array('username' => $response->username); if (isset($options['domain'])) { $credentials['domain'] = $options['domain']; } $adapter = SHFactory::getUserAdapter($credentials); // Get the authorising user dn $id = $adapter->getId(false); } catch (Exception $e) { // Configuration or authorisation failure $response->status = JAuthentication::STATUS_FAILURE; $response->error_message = JText::_('JGLOBAL_AUTH_NO_USER'); return; } try { // Let's get the user attributes $attributes = $adapter->getAttributes(); if (!is_array($attributes) || !count($attributes)) { // No attributes therefore error throw new Exception(JText::_('PLG_AUTHENTICATION_SHADAPTER_ERR_12611'), 12611); } } catch (Exception $e) { // Error getting user attributes. $response->status = JAuthentication::STATUS_FAILURE; $response->error_message = JText::_('PLG_AUTHENTICATION_SHADAPTER_ERR_12611'); // Process a error log SHLog::add($e, 12622, JLog::ERROR, 'auth'); return false; } // Set the required Joomla specific user fields with the returned User Adapter Attributes $response->username = $adapter->getUid(); $response->fullname = $adapter->getFullname(); $response->email = $adapter->getEmail(); // The adapter type needs to be set before returning the response $response->type = $adapter->getType(); if (SHFactory::getConfig()->get('user.nullpassword')) { // Do not store password in Joomla database $response->password_clear = ''; } /* * Everything appears to be a success and therefore we shall log the user login * then report back to the subject. */ SHLog::add(JText::sprintf('PLG_AUTHENTICATION_SHADAPTER_INFO_12612', $response->username), 12612, JLog::INFO, 'auth'); $retResponse->status = JAuthentication::STATUS_SUCCESS; unset($adapter); return $retResponse; }
public function onUserAfterSaveGroup($form, $table, $isNew) { $groupname = $table->title; $adapter = SHFactory::getGroupAdapter($groupname); $adapterName = $adapter::getName(); if ($isNew && $adapter->state === $adapter::STATE_CREATED) { // Update the group map linker //SHAdapterMap::setUser($adapter, $table->id); SHAdapterEventHelper::triggerEvent($adapterName, 'onGroupAfterSave', array($groupname, $isNew)); } elseif ($adapter->state !== $adapter::STATE_UNKNOWN) { SHAdapterEventHelper::triggerEvent($adapterName, 'onGroupAfterSave', array($groupname, $isNew)); } }
/** * Stage the profile to LDAP ready for committing. * * @param SimpleXMLElement $xml The XML profile to process. * @param string $username Username of profile owner to change. * @param array $profile Array of profile fields to save (key=>value). * * @return boolean True on success * * @since 2.0 * @throws Exception */ protected function saveProfileToLdap($xml, $username, $profile = array()) { // Setup the profile user in user adapter $adapter = SHFactory::getUserAdapter($username); $processed = array(); // Loop around each profile field foreach ($profile as $key => $value) { $delimiter = null; $xmlField = $xml->xpath("fieldset/field[@name='$key']"); if ($delimiter = (string) $xmlField[0]['delimiter']) { /* Multiple values - we will use a delimiter to represent * the extra data in Joomla. We also use a newline override * as this is probably going to be the most popular delimter. */ if (strToUpper($delimiter) == 'NEWLINE') { $delimiter = '\r\n|\r|\n'; } // Split up the delimited profile field $newValues = preg_split("/$delimiter/", $value); // Resave the split profile field into a new array set for ($i = 0; $i < count($newValues); ++$i) { $processed[$key][$i] = $newValues[$i]; } } else { // Single Value $processed[$key] = $value; } } if (count($processed)) { // Lets save the new (current) fields to the LDAP DN $adapter->setAttributes($processed); } return true; }
/** * Method for attempting single sign on. * * @return boolean True on successful SSO or False on failure. * * @since 2.0 */ protected function _attemptSSO() { // Check the required SSO libraries exist if (!(class_exists('SHSsoHelper') && class_exists('SHSso'))) { // Error: classes missing SHLog::add(JText::_('LIB_SHSSOMONITOR_ERR_15001'), 15001, JLog::ERROR, 'sso'); return; } try { $config = SHFactory::getConfig(); // Check if SSO is disabled via the session if (SHSsoHelper::status() !== SHSsoHelper::STATUS_ENABLE) { // It is disabled so do not continue return; } SHSsoHelper::enable(); $forceLogin = false; $userId = JFactory::getUser()->get('id'); if ($config->get('sso.forcelogin', false)) { if ($userId) { // Log out current user if detect user is not equal $forceLogin = true; } } else { if ($userId) { // User already logged in and no forcelogout return; } } /* * Lets check the IP rule is valid before we continue - * if the IP rule is false then SSO is not allowed here. */ jimport('joomla.application.input'); $input = new JInput($_SERVER); // Get the IP address of this client $myIp = $input->get('REMOTE_ADDR', false, 'string'); // Get a list of the IP addresses specific to the specified rule $ipList = json_decode($config->get('sso.iplist')); // Get the rule value $ipRule = $config->get('sso.iprule', SHSsoHelper::RULE_ALLOW_ALL); if (!SHSsoHelper::doIPCheck($myIp, $ipList, $ipRule)) { if (!$forceLogin) { // This IP isn't allowed SHLog::add(JText::_('LIB_SHSSO_DEBUG_15004'), 15004, JLog::DEBUG, 'sso'); } return; } /* * We are going to check if we are in backend. * If so then we need to check if sso is allowed * to execute on the backend. */ if (JFactory::getApplication()->isAdmin()) { if (!$config->get('sso.backend', false)) { if (!$forceLogin) { // Not allowed to SSO on backend SHLog::add(JText::_('LIB_SHSSO_DEBUG_15006'), 15006, JLog::DEBUG, 'sso'); } return; } } // Instantiate the main SSO library for detection & authentication $sso = new SHSso($config->get('sso.plugintype', 'sso')); $detection = $sso->detect(); if ($detection) { // Check the detected user is not blacklisted $blacklist = (array) json_decode($config->get('user.blacklist')); if (in_array($detection['username'], $blacklist)) { SHLog::add(JText::sprintf('LIB_SHSSO_DEBUG_15007', $detection['username']), 15007, JLog::DEBUG, 'sso'); // Detected user is blacklisted return; } // Check if the current logged in user matches the detection if ($forceLogin && strtolower($detection['username']) != strtolower(JFactory::getUser()->get('username'))) { SHLog::add(JText::sprintf('LIB_SHSSO_DEBUG_15008', $detection['username']), 15008, JLog::DEBUG, 'sso'); // Need to logout the current user JFactory::getApplication()->logout(); } } // Attempt the login return $sso->login($detection); } catch (Exception $e) { SHLog::add($e, 15002, JLog::ERROR, 'sso'); } }
/** * Method to get a JDatabaseQuery object for retrieving the data set from a database. * * @return JDatabaseQuery A JDatabaseQuery object to retrieve the data set. * * @since 2.0 */ public function getListQuery() { // Create a new query object. $db = $this->getDbo(); $query = $db->getQuery(true); // Select the required fields from the table. $query->select($db->escape($this->getState('list.select', 'a.*'))); $query->from($db->quoteName(SHFactory::getConfig()->get('ldap.table', '#__sh_ldap_config')) . ' AS a'); // Filter the items over the search string if set. $search = $this->getState('filter.search'); if (!empty($search)) { if (stripos($search, 'id:') === 0) { $query->where($db->quoteName('a.id') . ' = ' . $db->quote((int) substr($search, 3))); } else { // Note: * we use an escape so no quote required * $search = $db->quote('%' . $db->escape($search, true) . '%'); $query->where('(' . $db->quoteName('name') . ' LIKE ' . $search . ')'); } } // Add the list ordering clause. $query->order($db->escape($this->getState('list.ordering', 'ordering')) . ' ' . $db->escape($this->getState('list.direction', 'ASC'))); return $query; }
/** * 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)); }
/** * Method to save the form data. * * @param array $data The form data. * * @return boolean True on success, False on error. * * @since 11.1 */ public function save($data) { // Initialise variables; $table = $this->getTable(); $key = $table->getKeyName(); $pk = !empty($data[$key]) ? $data[$key] : (int) $this->getState($this->getName() . '.id'); $isNew = true; // Unset some debug data unset($data['debug_full']); unset($data['debug_username']); unset($data['debug_password']); // Allow an exception to be thrown. try { // Load the row if saving an existing record. if ($pk > 0) { $table->load($pk); $isNew = false; } // Sets a default proxy encryption flag in the table $table->proxy_encryption = isset($table->proxy_encryption) ? $table->proxy_encryption : false; // Deal with the proxy encryption if the password has changed if (isset($data['proxy_encryption']) && $data['proxy_encryption'] && (!$table->proxy_encryption || $table->proxy_password != $data['proxy_password'])) { $crypt = SHFactory::getCrypt(); $data['proxy_password'] = $crypt->encrypt($data['proxy_password']); } } catch (Exception $e) { $this->setError($e->getMessage()); return false; } return parent::save($data); }
/** * Called during a ldap synchronisation. * * Checks to ensure that required variables are set before calling the main * do mapping library routine. * * @param JUser &$instance A JUser object for the authenticating user. * @param array $options Array holding options. * * @return boolean True on success * * @since 2.0 */ public function onLdapSync(&$instance, $options = array()) { if (!$this->doSetup()) { return; } try { // Gather the user adapter $username = $instance->username; $adapter = SHFactory::getUserAdapter($username); // Get the distinguished name of the user $dn = $adapter->getId(false); /* * Process the ldap attributes created from the source ldap * user into mapping entries, then evaulate which groups * are of interest when compared to the parameter list. */ $attribute = $this->lookup_type === self::LOOKUP_FORWARD ? $this->memberof_attribute : $this->member_attribute; $attributes = $adapter->getAttributes($attribute); $userGroups = JArrayHelper::getValue($attributes, $attribute); if (!(is_array($userGroups) && count($userGroups))) { // No groups to process SHLog::add(JText::sprintf('PLG_LDAP_MAPPING_DEBUG_12008', $username), 12008, JLog::DEBUG, 'ldap'); return; } $ldapUser = new SHLdapMappingEntry($dn, $userGroups, $this->dn_validate); // Do the actual compare $mapList = SHLdapMappingEntry::compareGroups($this->entries, $ldapUser); $changes = false; // Check if add groups are allowed if ($this->addition) { /* * Find the groups that require adding then add them to the JUser * instance. Any errors will results in the entire method failing. */ $toAdd = self::getGroupsToAdd($instance, $mapList); foreach ($toAdd as $group) { SHLog::add(JText::sprintf('PLG_LDAP_MAPPING_DEBUG_12011', $group, $username), 12011, JLog::DEBUG, 'ldap'); SHUserHelper::addUserToGroup($instance, $group); $changes = true; } } // Check if removal of groups are allowed if ($this->removal !== self::NO) { /* * Find the groups that require removing then remove them from the * JUser instance. */ $toRemove = self::getGroupsToRemove($instance, $mapList, $this->managed); foreach ($toRemove as $group) { SHLog::add(JText::sprintf('PLG_LDAP_MAPPING_DEBUG_12013', $group, $username), 12013, JLog::DEBUG, 'ldap'); SHUserHelper::removeUserFromGroup($instance, $group); $changes = true; } } /* If we have no groups left in our user then we must add * the public group otherwise Joomla won't save the changes * to the database. */ if (!count($instance->get('groups'))) { SHUserHelper::addUserToGroup($instance, $this->public_id); $changes = true; } if ($changes) { return true; } return; } catch (Exception $e) { SHLog::add($e, 12021, JLog::ERROR, 'ldap'); return false; } }
/** * Gets the configuration options for the platform. * * @param string $type The type of configuration (i.e. sql, file). * @param array $options An array of options (handler=>[Database Object], * table=>[Database Table], file=>[path to file], namespace=>[Namespace of Class]). * * @return JRegistry Registry of the configuration options. * * @since 2.0 */ public static function getConfig($type = 'sql', $options = array()) { if (!isset(self::$config)) { if ($type === 'sql') { $options['handler'] = isset($options['handler']) ? $options['handler'] : null; if (!isset($options['table'])) { // Uses the default table name $options['table'] = '#__sh_config'; } // Retrieve the platform config via cached SQL $cache = JFactory::getCache('shplatform', 'callback'); self::$config = $cache->get(array(__CLASS__, 'createDBConfig'), array($options['handler'], $options['table']), null); } elseif ($type === 'file') { if (!isset($options['file'])) { // Attempt to use a default file $options['file'] = JPATH_ROOT . '/sh_configuration.php'; } if (!isset($options['namespace'])) { // Attempt to use a default file $options['namespace'] = null; } // Retrieve the platform config via PHP file self::$config = self::createFileConfig($options['file'], $options['namespace']); } } return self::$config; }
if (!defined('SHLDAP_VERSION')) { // Define the JMapMyLDAP version define('SHLDAP_VERSION', SHFactory::getConfig()->get('ldap.version')); } // Load the global Ldap language file JFactory::getLanguage()->load('shmanic_ldap', JPATH_ROOT); // Push the reqcert setting if defined if ($reqcert = (int) SHFactory::getConfig()->get('ldap.reqcert', 0)) { if ($reqcert === 1) { putenv('LDAPTLS_REQCERT=never'); } elseif ($reqcert === 2) { putenv('LDAPTLS_REQCERT=allow'); } elseif ($reqcert === 3) { putenv('LDAPTLS_REQCERT=try'); } elseif ($reqcert === 4) { putenv('LDAPTLS_REQCERT=hard'); } } // Setup and get the Ldap dispatcher $dispatcher = SHFactory::getDispatcher('ldap'); // Start the LDAP event debugger only if global jdebug is switched on if (defined('JDEBUG') && JDEBUG && class_exists('SHLdapEventDebug')) { new SHLdapEventDebug($dispatcher); } // Import the Ldap group and use the ldap dispatcher JPluginHelper::importPlugin('ldap', null, true, $dispatcher); // Employ the event bouncer to control the global Joomla event triggers if (class_exists('SHLdapEventBouncer')) { $dispatcher = JDispatcher::getInstance(); $instance = new SHLdapEventBouncer($dispatcher); }
/** * Entry point for the script. * * @return void * * @since 2.0 */ public function doExecute() { // Setup some stats $failed = 0; $success = 0; $errors = array(); // It appears we have to tell the system we are running with the site otherwise bad things happen JFactory::getApplication('site'); $this->out(JText::_('CLI_SHMANIC_LDAP_INFO_13001')); // Get all the valid configurations if (!($configs = SHLdapHelper::getConfig())) { // Failed to find any Ldap configs $this->out(JText::_('CLI_SHMANIC_LDAP_ERR_13003')); $this->close(1); } // Check if only a single config was found if ($configs instanceof JRegistry) { /* * To make things easier, we pretend we returned multiple Ldap configs * by casting the single entry into an array. */ $configs = array($configs); } $count = count($configs); $this->out(JText::sprintf('CLI_SHMANIC_LDAP_INFO_13002', $count))->out(); // Loop around each LDAP configuration foreach ($configs as $config) { try { // Get a new Ldap object $ldap = new SHLdap($config); // Bind with the proxy user if (!$ldap->authenticate(SHLdap::AUTH_PROXY)) { // Something is wrong with this LDAP configuration - cannot bind to proxy user $errors[] = new Exception(JText::sprintf('CLI_SHMANIC_LDAP_ERR_13011', $ldap->info), 13011); unset($ldap); continue; } // Get all the Ldap users in the directory if (!($result = $ldap->search(null, $ldap->allUserFilter, array('dn', $ldap->keyUid)))) { // Failed to search for all users in the directory $errors[] = new Exception(JText::sprintf('CLI_SHMANIC_LDAP_ERR_13012', $ldap->getErrorMsg()), 13012); unset($ldap); continue; } // Loop around each Ldap user for ($i = 0; $i < $result->countEntries(); ++$i) { // Get the Ldap username (case insensitive) if (!($username = strtolower($result->getValue($i, $ldap->keyUid, 0)))) { continue; } try { // Check if this user is in the blacklist if ($blacklist = (array) json_decode(SHFactory::getConfig()->get('user.blacklist'))) { if (in_array($username, $blacklist)) { throw new RuntimeException(JText::_('CLI_SHMANIC_LDAP_ERR_13025'), 13025); } } // Create the new user adapter $adapter = new SHUserAdaptersLdap(array('username' => $username), $config); // Get the Ldap DN if (!($dn = $adapter->getId(false))) { continue; } $this->out(JText::sprintf('CLI_SHMANIC_LDAP_INFO_13020', $username)); // Get the Ldap user attributes $source = $adapter->getAttributes(); // Get the core mandatory J! user fields $username = $adapter->getUid(); $fullname = $adapter->getFullname(); $email = $adapter->getEmail(); if (empty($fullname)) { // Full name doesnt exist; use the username instead $fullname = $username; } if (empty($email)) { // Email doesnt exist; cannot proceed throw new Exception(JText::_('CLI_SHMANIC_LDAP_ERR_13022'), 13022); } // Create the user array to enable creating a JUser object $user = array('fullname' => $fullname, 'username' => $username, 'password_clear' => null, 'email' => $email); // Create a JUser object from the Ldap user $options = array('adapter' => &$adapter); $instance = SHUserHelper::getUser($user, $options); if ($instance === false) { // Failed to get the user either due to save error or autoregister throw new Exception(JText::_('CLI_SHMANIC_LDAP_ERR_13024'), 13024); } // Fire the Ldap specific on Sync feature $sync = SHLdapHelper::triggerEvent('onLdapSync', array(&$instance, $options)); // Check if the synchronise was successfully and report if ($sync !== false) { // Even if the sync does not need a save, do it anyway as Cron efficiency doesnt matter too much SHUserHelper::save($instance); // Update the user map linker SHAdapterMap::setUser($adapter, $instance->id); // Above should throw an exception on error so therefore we can report success $this->out(JText::sprintf('CLI_SHMANIC_LDAP_INFO_13029', $username)); ++$success; } else { throw new Exception(JText::_('CLI_SHMANIC_LDAP_ERR_13026'), 13026); } unset($adapter); } catch (Exception $e) { unset($adapter); ++$failed; $errors[] = new Exception(JText::sprintf('CLI_SHMANIC_LDAP_ERR_13028', $username, $e->getMessage()), $e->getCode()); } } } catch (Exception $e) { $errors[] = new Exception(JText::_('CLI_SHMANIC_LDAP_ERR_13004'), 13004); } } // Print out some results and stats $this->out()->out()->out(JText::_('CLI_SHMANIC_LDAP_INFO_13032'))->out(); $this->out(JText::_('CLI_SHMANIC_LDAP_INFO_13038')); foreach ($errors as $error) { if ($error instanceof Exception) { $this->out(' ' . $error->getCode() . ': ' . $error->getMessage()); } else { $this->out(' ' . (string) $error); } } $this->out()->out(JText::sprintf('CLI_SHMANIC_LDAP_INFO_13034', $success)); $this->out(JText::sprintf('CLI_SHMANIC_LDAP_INFO_13036', $failed)); $this->out()->out('============================'); }
/** * Calls the logoutRemoteUser method within SSO plug-in if the user * was logged on with SSO. * * @return void * * @since 2.0 */ public function logout() { $session = JFactory::getSession(); $app = JFactory::getApplication(); // Get the SSO plug-in name from login if we used SSO if ($class = $session->get(SHSsoHelper::SESSION_PLUGIN_KEY, false)) { // Lets disable SSO until the user requests login SHSsoHelper::disable(); $router = $app->getRouter(); // We need to add a callback on the router to tell the routed page we just logged out from SSO $router->setVar('ssologoutkey', SHFactory::getConfig()->get('sso.bypasskey', 'nosso')); $router->setVar('ssologoutval', $session->get(SHSsoHelper::SESSION_STATUS_KEY, SHSsoHelper::STATUS_ENABLE)); $router->attachBuildRule('SHSso::logoutRouterRule'); $index = array_search($class, $this->_observers); // Ensure the SSO plug-in is still available if ($index !== false && method_exists($this->_observers[$index], 'logoutRemoteUser')) { $this->_observers[$index]->logoutRemoteUser(); } } }
/** * Returns all the Ldap configured IDs and names in an associative array * where [id] => [name]. * * @param JRegistry $registry Platform configuration. * * @return Array Array of configured IDs * * @since 2.0 */ public static function getConfigIDs($registry = null) { // Get the Ldap configuration from the factory $registry = is_null($registry) ? SHFactory::getConfig() : $registry; // Get the Ldap configuration source (e.g. sql | plugin | file) $source = (int) $registry->get('ldap.config', self::CONFIG_SQL); if ($source === self::CONFIG_SQL) { // Get the database table using the sh_ldap_config as default $table = $registry->get('ldap.table', '#__sh_ldap_config'); // Get the global JDatabase object $db = JFactory::getDbo(); $query = $db->getQuery(true); // Do the SQL query $query->select($db->quoteName('id'))->select($db->quoteName('name'))->from($db->quoteName($table))->where($db->quoteName('enabled') . ' >= ' . $db->quote('1')); $db->setQuery($query); // Execute the query $results = $db->loadAssocList('id', 'name'); return $results; } elseif ($source === self::CONFIG_FILE) { // Grab the LDAP configuration file path from the registry and include it if ($file = $registry->get('ldap.file', JPATH_CONFIGURATION . '/ldap.php')) { @(include_once $file); } // Lets find all classes in the LDAP configuration file $classes = array_values(preg_grep('/(' . self::CONFIG_PREFIX . '){1}\\w*/i', get_declared_classes())); if (!empty($classes)) { $namespaces = $classes; // Retrieve the namespaces from the classes foreach ($namespaces as &$namespace) { $namespace = str_ireplace(self::CONFIG_PREFIX, '', $namespace); } return $namespaces; } // There are no namespaces, there return an array with one null element return array(null); } }
/** * TODO: move to a SHPlatform specific test in the future */ public function testSHPlatformFactoryBadConfig() { $this->setExpectedException('RuntimeException', 'LIB_SHPLATFORM_ERR_1121', 1121); $platform = SHFactory::getConfig('file', array('file' => static::PLATFORM_CONFIG_FILE, 'namespace' => 'asdas')); }
/** * Gets the configuration options for the platform. * * @param string $type The type of configuration (i.e. sql, file). * @param array $options An array of options (handler=>[Database Object], * table=>[Database Table], file=>[path to file], namespace=>[Namespace of Class]). * * @return JRegistry Registry of the configuration options. * * @since 2.0 */ public static function getConfig($type = 'sql', $options = array()) { if (!isset(self::$config)) { if ($type === 'sql') { if (!isset($options['handler'])) { // Uses the default Joomla database object $options['handler'] = JFactory::getDbo(); } if (!isset($options['table'])) { // Uses the default table name $options['table'] = '#__sh_config'; } // Retrieve the platform config via SQL self::$config = self::createDBConfig($options['handler'], $options['table']); } elseif ($type === 'file') { if (!isset($options['file'])) { // Attempt to use a default file $options['file'] = JPATH_ROOT . '/sh_configuration.php'; } if (!isset($options['namespace'])) { // Attempt to use a default file $options['namespace'] = null; } // Retrieve the platform config via PHP file self::$config = self::createFileConfig($options['file'], $options['namespace']); } } return self::$config; }
/** * Returns whether SSO is allowed to perform actions in the current session. * * @return integer True if session is enabled or False if SSO disabled. * * @since 1.0 */ public static function status() { $config = SHFactory::getConfig(); $behaviour = (int) $config->get('sso.behaviour', 1); $status = JFactory::getSession()->get(self::SESSION_STATUS_KEY, false); if ($status === false) { $status = self::STATUS_ENABLE; } $status = (int) $status; if ($status === self::STATUS_BYPASS_DISABLE) { if ($behaviour !== 1) { // Manual bypass is activated return self::STATUS_BYPASS_DISABLE; } } elseif ($behaviour === 2 || $behaviour === 0) { $formLogin = true; // Get the login tasks and check if username can be null to sso $tasks = json_decode($config->get('sso.logintasks', '[]')); $usernameField = $config->get('sso.checkusernull', true); // Check if the URL contains this key and the value assigned to it $input = new JInput(); $task = $input->get('task', false); if (!in_array($task, $tasks) || !JSession::checkToken() || $usernameField && $input->get('username', null)) { $formLogin = false; } if ($status === self::STATUS_LOGOUT_DISABLE) { // Logout bypass is activated if (!$formLogin) { return self::STATUS_LOGOUT_DISABLE; } } elseif ($status === self::STATUS_ENABLE) { if ($behaviour === 0 && !$formLogin) { return self::STATUS_BEHAVIOUR_DISABLED; } } } // Default to SSO enabled return self::STATUS_ENABLE; }
/** * Method is called after user data is stored in the database. * * @param array $user Holds the new user data. * @param boolean $isNew True if a new user has been stored. * @param boolean $success True if user was successfully stored in the database. * @param string $msg An error message. * * @return void * * @since 2.0 */ public function onUserAfterSave($user, $isNew, $success, $msg) { if ($this->isLdap) { if ($isNew && $success) { // Ensure Joomla knows this is a new Ldap user $adapter = SHFactory::getUserAdapter($user['username']); $options = array('adapter' => &$adapter); $instance = SHUserHelper::getUser($user, $options); // Silently resave the user without calling the onUserSave events SHUserHelper::save($instance, false); } SHLdapHelper::triggerEvent('onUserAfterSave', array($user, $isNew, $success, $msg)); JFactory::getSession()->clear('created', 'ldap'); } }
/** * This method returns a user object. If options['autoregister'] is true, * and if the user doesn't exist, then it'll be created. * * @param array $user Holds the user data. * @param array &$options Array holding options (remember, autoregister, group). * * @return JUser A JUser object containing the user. * * @since 1.0 * @throws Exception */ public static function getUser(array $user, &$options = array()) { $instance = JUser::getInstance(); if (isset($options['adapter'])) { // Tell the getUser to store the auth_type and auth_config based on whats inside the adapter $options['type'] = isset($options['type']) ? $options['type'] : $options['adapter']::getType(); $options['domain'] = isset($options['domain']) ? $options['domain'] : $options['adapter']->getDomain(); } // Check if the user already exists in the database if ($id = intval(JUserHelper::getUserId($user['username']))) { $instance->load($id); // Inject the type and domain into this object if they are set if (isset($options['type'])) { if ($instance->getParam(self::PARAM_AUTH_TYPE) != $options['type']) { $options['change'] = true; $instance->setParam(self::PARAM_AUTH_TYPE, $options['type']); } } if (isset($options['domain'])) { if ($instance->getParam(self::PARAM_AUTH_DOMAIN) != $options['domain']) { $options['change'] = true; $instance->setParam(self::PARAM_AUTH_DOMAIN, $options['domain']); } } return $instance; } // ** The remainder of this method is for new users only ** $config = SHFactory::getConfig(); // Deal with auto registration flags $autoRegister = (int) $config->get('user.autoregister', 1); if ($autoRegister === 0 || $autoRegister === 1) { // Inherited Auto-registration $options['autoregister'] = isset($options['autoregister']) ? $options['autoregister'] : $autoRegister; } else { // Override Auto-registration $options['autoregister'] = ($autoRegister === 2) ? 1 : 0; } // Deal with the default group jimport('joomla.application.component.helper'); $comUsers = JComponentHelper::getParams('com_users', true); if ($comUsers === false) { // Check if there is a default set in the SHConfig $defaultUserGroup = $config->get('user.defaultgroup', 2); } else { // Respect Joomla's default user group $defaultUserGroup = $comUsers->get('new_usertype', 2); } // Setup the user fields for this new user $instance->set('id', 0); $instance->set('name', $user['fullname']); $instance->set('username', $user['username']); $instance->set('password_clear', $user['password_clear']); $instance->set('email', $user['email']); $instance->set('usertype', 'depreciated'); $instance->set('groups', array($defaultUserGroup)); // Set the User Adapter parameters if (isset($options['type'])) { $instance->setParam(self::PARAM_AUTH_TYPE, $options['type']); } if (isset($options['domain'])) { $instance->setParam(self::PARAM_AUTH_DOMAIN, $options['domain']); } // If autoregister is set, register the user if ($options['autoregister']) { if (!self::save($instance)) { // Failed to save the user to the database throw new Exception(JText::sprintf('LIB_SHUSERHELPER_ERR_10501', $user['username'], $instance->getError()), 10501); } } else { // We don't want to proceed if autoregister is not enabled throw new Exception(JText::sprintf('LIB_SHUSERHELPER_ERR_10502', $user['username']), 10502); } return $instance; }
/** * Method is called after user data is stored in the database. * * Deletes the user if they're new and Joomla user creation failed. * * @param array $user Holds the new user data. * @param boolean $isNew True if a new user has been stored. * @param boolean $success True if user was successfully stored in the database. * @param string $msg An error message. * * @return void * * @since 2.0 */ public function onUserAfterSave($user, $isNew, $success, $msg) { if ($isNew && !$success && $this->params->get('onfail_delete', false) && $this->username) { try { // Check the session to ensure this user was created successfully last time if (JFactory::getSession()->get('creation', null, 'ldap') == $this->username) { $adapter = SHFactory::getUserAdapter($this->username); $adapter->delete(); SHLog::add(JTest::sprintf('PLG_LDAP_CREATION_INFO_12826', $this->username), 12826, JLog::INFO, 'ldap'); } } catch (Exception $e) { SHLog::add($e, 12803, JLog::ERROR, 'ldap'); } $this->username = null; } }
/** * Class Constructor. * * @param object $configObj An object of configuration variables. * * @since 2.0 */ public function __construct($configObj = null) { if (is_null($configObj)) { // Parameters will need setting later $configArr = array(); } elseif ($configObj instanceof JRegistry) { // JRegistry object needs to be converted to an array $configArr = $configObj->toArray(); } elseif (is_array($configObj)) { // The parameter was an array already $configArr = $configObj; } else { // Unknown format throw new InvalidArgumentException(JText::_('LIB_SHLDAP_ERR_990'), 990); } // Assign the configuration to their respected class properties only if they exist foreach ($configArr as $k => $v) { if (property_exists($this, $k)) { $this->$k = $v; } else { $this->extras[$k] = $v; } } // Check the Ldap extension is loaded if (!extension_loaded('ldap')) { // Ldap extension is not loaded throw new RunTimeException(JText::_('LIB_SHLDAP_ERR_991'), 991); } // Reset resource & debug $this->resource = null; $this->debug = array(); // Unencrypt the proxy user if required if ($this->proxy_encryption && !empty($this->proxy_password)) { if (!empty($this->encryption_options)) { $this->encryption_options = (array) json_decode($this->encryption_options); } // There is password encryption lets decrypt (this is only basic) $crypt = SHFactory::getCrypt($this->encryption_options); $this->proxy_password = $crypt->decrypt($this->proxy_password); } }