/** * Processes the password set form * * @return void */ public function settingpasswordTask() { // Check for request forgeries Session::checkToken('post') or exit(Lang::txt('JINVALID_TOKEN')); // Get the token and user id from the verification process $token = User::getState('com_users.reset.token', null); $id = User::getState('com_users.reset.user', null); $no_html = Request::getInt('no_html', 0); // Check the token and user id if (empty($token) || empty($id)) { throw new Exception(Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_TOKENS_MISSING'), 403); } // Get the user object $user = \Hubzero\User\User::oneOrFail($id); // Check for a user and that the tokens match if ($user->tokens()->latest()->token !== $token) { App::redirect(Route::url('index.php?option=' . $this->_option . '&task=setpassword', false), Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_USER_NOT_FOUND'), 'warning'); return; } // Make sure the user isn't blocked if ($user->get('block')) { App::redirect(Route::url('index.php?option=' . $this->_option . '&task=setpassword', false), Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_USER_NOT_FOUND'), 'warning'); return; } if (\Hubzero\User\Helper::isXDomainUser($user->get('id'))) { throw new Exception(Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_LINKED_ACCOUNT'), 403); } $password_rules = \Hubzero\Password\Rule::all()->whereEquals('enabled', 1)->rows(); $password1 = trim(Request::getVar('password1', null)); $password2 = trim(Request::getVar('password2', null)); if (!empty($password1)) { $msg = \Hubzero\Password\Rule::verify($password1, $password_rules, $user->get('username')); } else { $msg = array(); } require_once dirname(dirname(__DIR__)) . DS . 'helpers' . DS . 'utility.php'; $error = false; $changing = true; if (!$password1 || !$password2) { $error = Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_PASSWORD_TWICE'); } elseif ($password1 != $password2) { $error = Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_PASSWORD_DONT_MATCH'); } elseif (!\Components\Members\Helpers\Utility::validpassword($password1)) { $error = Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_PASSWORD_INVALID'); } elseif (!empty($msg)) { $error = Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_PASSWORD_FAILS_REQUIREMENTS'); } // If we're resetting password to the current password, just return true // That way you can't reset the counter on your current password, or invalidate it by putting it into history if (\Hubzero\User\Password::passwordMatches($user->get('id'), $password1)) { $error = false; $changing = false; $result = true; } if ($error) { if ($no_html) { $response = array('success' => false, 'message' => $error); echo json_encode($response); die; } else { App::redirect(Route::url('index.php?option=' . $this->_option . '&task=setpassword', false), $error, 'warning'); return; } } if ($changing) { // Encrypt the password and update the profile $result = \Hubzero\User\Password::changePassword($user->get('username'), $password1); } // Save the changes if (!$result) { if ($no_html) { $response = array('success' => false, 'message' => Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_GENERIC')); echo json_encode($response); die; } else { App::redirect(Route::url('index.php?option=' . $this->_option . '&task=setpassword', false), Lang::txt('COM_MEMBERS_CREDENTIALS_ERROR_GENERIC'), 'warning'); return; } } // Flush the user data from the session User::setState('com_users.reset.token', null); User::setState('com_users.reset.user', null); if ($no_html) { $response = array('success' => true, 'redirect' => Route::url('index.php?option=com_users&view=login', false)); echo json_encode($response); die; } else { // Everything went well...go to the login page App::redirect(Route::url('index.php?option=com_users&view=login', false), Lang::txt('COM_MEMBERS_CREDENTIALS_PASSWORD_RESET_COMPLETE'), 'passed'); } }
/** * Validate a password * * @param string $password * @param array $rules * @param mixed $user * @param string $name * @return array */ public static function verify($password, $rules, $user, $name = null) { if (empty($rules)) { return array(); } $fail = array(); $stats = self::analyze($password); foreach ($rules as $rule) { if ($rule['rule'] == 'minCharacterClasses') { if ($stats['uniqueClasses'] < $rule['value']) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'maxCharacterClasses') { if ($stats['uniqueClasses'] > $rule['value']) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'minPasswordLength') { if ($stats['count'][0] < $rule['value']) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'maxPasswordLength') { if ($stats['count'][0] > $rule['value']) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'maxClassCharacters') { if (empty($rule['class'])) { continue; } $class = $rule['class']; if (empty($stats['count'][$class])) { $stats['count'][$class] = 0; } if ($stats['count'][$class] > $rule['value']) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'minClassCharacters') { if (empty($rule['class'])) { continue; } $class = $rule['class']; if (empty($stats['count'][$class])) { $stats['count'][$class] = 0; } if ($stats['count'][$class] < $rule['value']) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'minUniqueCharacters') { if ($stats['uniqueCharacters'] < $rule['value']) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'notBlacklisted') { if (Blacklist::basedOnBlackList($password)) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'notNameBased') { if ($name == null) { if (is_numeric($user)) { $xuser = User::oneOrNew($user); } else { $xuser = User::oneByUsername($user); } if (!is_object($xuser)) { continue; } $givenName = $xuser->get('givenName'); $middleName = $xuser->get('middleName'); $surname = $xuser->get('surname'); $name = $givenName; if (!empty($middleName)) { if (empty($name)) { $name = $middleName; } else { $name .= ' ' . $middleName; } } if (!empty($surname)) { if (empty($name)) { $name = $surname; } else { $name .= ' ' . $surname; } } } if (self::isBasedOnName($password, $name)) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'notUsernameBased') { if (is_numeric($user)) { $xuser = User::oneOrNew($user); if (!is_object($xuser)) { continue; } $user = $xuser->get('username'); } if (self::isBasedOnUsername($password, $user)) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'notReused') { $date = new \DateTime('now'); $date->modify("-" . $rule['value'] . "day"); $phist = History::getInstance($user); if (!is_object($phist)) { continue; } if ($phist->exists($password, $date->format("Y-m-d H:i:s"))) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] == 'notRepeat') { if (Password::passwordMatches($user, $password, true)) { $fail[] = $rule['failuremsg']; } } else { if ($rule['rule'] === 'true') { } else { if ($rule['rule'] == 'notStale') { } else { $fail[] = $rule['failuremsg']; } } } } } } } } } } } } } } } if (empty($fail)) { $fail = array(); } return $fail; }
</legend> <label<?php echo $this->change && $this->oldpass && !\Hubzero\User\Password::passwordMatches($this->profile->get('uidNumber'), $this->oldpass, true) ? ' class="fieldWithErrors"' : ''; ?> > <?php echo Lang::txt('COM_MEMBERS_FIELD_CURRENT_PASS'); ?> <input name="oldpass" id="oldpass" type="password" value="" /> </label> <?php if ($this->change && !$this->oldpass) { echo '<p class="error">' . Lang::txt('COM_MEMBERS_PASS_BLANK') . '</p>'; } if ($this->change && $this->oldpass && !\Hubzero\User\Password::passwordMatches($this->profile->get('uidNumber'), $this->oldpass, true)) { echo '<p class="error">' . Lang::txt('COM_MEMBERS_PASS_INCORRECT') . '</p>'; } ?> <div class="grid"> <div class="col span6"> <label<?php echo $this->change && (!$this->newpass || $this->newpass != $this->newpass2) ? ' class="fieldWithErrors"' : ''; ?> > <?php echo Lang::txt('COM_MEMBERS_FIELD_NEW_PASS'); ?> <input name="newpass" id="newpass" type="password" value="" /> <?php
/** * Check user credentials * * @param string $username User's username * @param string $password User's password * @return bool Result of username/password check */ public function checkUserCredentials($username, $password) { // allow authentication via email, just like in the hub if (strpos($username, '@')) { $username = $this->getUsernameFromEmail($username); } // use hubzero password library to compare stored password with sent password $match = Password::passwordMatches($username, $password, true); // return if match was found return (bool) $match; }
/** * This method should handle any authentication and report 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 */ public function onUserAuthenticate($credentials, $options, &$response) { jimport('joomla.user.helper'); // For JLog $response->type = 'hubzero'; // HUBzero does not like blank passwords if (empty($credentials['password'])) { $response->status = \Hubzero\Auth\Status::FAILURE; $response->error_message = Lang::txt('PLG_AUTHENTICATION_HUBZERO_ERROR_EMPTY_PASS'); return false; } // Initialize variables $conditions = ''; // Get a database object $db = \App::get('db'); // Determine if attempting to log in via username or email address if (strpos($credentials['username'], '@')) { $conditions = ' WHERE email=' . $db->Quote($credentials['username']); } else { $conditions = ' WHERE username='******'username']); } $query = 'SELECT `id`, `username`, `password`' . ' FROM `#__users`' . $conditions . ' AND `block` != 1'; $db->setQuery($query); $result = $db->loadObjectList(); if (is_array($result) && count($result) > 1) { $response->status = \Hubzero\Auth\Status::FAILURE; $response->error_message = Lang::txt('PLG_AUTHENTICATION_HUBZERO_UNKNOWN_USER'); return false; } elseif (is_array($result) && isset($result[0])) { $result = $result[0]; } // Now make sure they haven't made too many failed login attempts if (\Hubzero\User\User::oneOrFail($result->id)->hasExceededLoginLimit()) { $response->status = \Hubzero\Auth\Status::FAILURE; $response->error_message = Lang::txt('PLG_AUTHENTICATION_HUBZERO_TOO_MANY_ATTEMPTS'); return false; } if ($result) { if (\Hubzero\User\Password::passwordMatches($result->username, $credentials['password'], true)) { $user = User::getInstance($result->id); $response->username = $user->username; $response->email = $user->email; $response->fullname = $user->name; $response->status = \Hubzero\Auth\Status::SUCCESS; $response->error_message = ''; // Check validity and age of password $password_rules = \Hubzero\Password\Rule::getRules(); $msg = \Hubzero\Password\Rule::validate($credentials['password'], $password_rules, $result->username); if (is_array($msg) && !empty($msg[0])) { App::get('session')->set('badpassword', '1'); } if (\Hubzero\User\Password::isPasswordExpired($result->username)) { App::get('session')->set('expiredpassword', '1'); } // Set cookie with login preference info $prefs = array('user_id' => $user->get('id'), 'user_img' => \Hubzero\User\Profile::getInstance($user->get('id'))->getPicture(0, false), 'authenticator' => 'hubzero'); $namespace = 'authenticator'; $lifetime = time() + 365 * 24 * 60 * 60; \Hubzero\Utility\Cookie::bake($namespace, $lifetime, $prefs); } else { $response->status = \Hubzero\Auth\Status::FAILURE; $response->error_message = Lang::txt('PLG_AUTHENTICATION_HUBZERO_AUTHENTICATION_FAILED'); } } else { $response->status = \Hubzero\Auth\Status::FAILURE; $response->error_message = Lang::txt('PLG_AUTHENTICATION_HUBZERO_AUTHENTICATION_FAILED'); } }
/** * Short description for 'access_token' * * Long description (if any) ... * * @return unknown Return description (if any) ... */ private function access_token() { if (empty($this->_provider)) { $this->_response->setResponseProvides('application/x-www-form-urlencoded,text/html;q=0.9'); $this->_response->setErrorMessage('oauth_problem=bad oauth provider', 501, 'Internal Server Error'); return; } JLoader::import('Hubzero.User.Password'); $xauth_request = false; $header = ''; if (isset($_SERVER['HTTP_AUTHORIZATION'])) { $header = $_SERVER['HTTP_AUTHORIZATION']; } // @FIXME: header check is inexact and could give false positives // @FIXME: pecl oauth provider doesn't handle x_auth in header // @FIXME: api application should convert xauth variables in // header to form/query data as workaround // @FIXME: this code is here for future use if/when pecl oauth // provider is fixed // if (isset($_GET['x_auth_mode']) || isset($_GET['x_auth_username']) || isset($_GET['x_auth_password']) || isset($_POST['x_auth_mode']) || isset($_POST['x_auth_username']) || isset($_POST['x_auth_password']) || strpos($header, 'x_auth_mode') !== false || strpos($header, 'x_auth_username') !== false || strpos($header, 'x_auth_mode') !== false) { $xauth_request = true; } if ($xauth_request) { if ($this->_provider->getConsumerData()->xauth == '0') { $this->_response->setResponseProvides('application/x-www-form-urlencoded,text/html;q=0.9'); $this->_response->setErrorMessage('oauth_problem=permission_denied', 401, 'Unauthorized0'); return; } if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'off') { $this->_response->setErrorMessage('SSL Required', 403, 'Forbidden'); return; } if (isset($this->_provider->x_auth_mode)) { $x_auth_mode = $this->_provider->x_auth_mode; } else { if (isset($_POST['x_auth_mode'])) { $x_auth_mode = $_POST['x_auth_mode']; } else { if (isset($_GET['x_auth_mode'])) { $x_auth_mode = $_GET['x_auth_mode']; } else { $x_auth_mode = ''; } } } if (isset($this->_provider->x_auth_username)) { $x_auth_username = $this->_provider->x_auth_username; } else { if (isset($_POST['x_auth_username'])) { $x_auth_username = $_POST['x_auth_username']; } else { if (isset($_GET['x_auth_username'])) { $x_auth_username = $_GET['x_auth_username']; } else { $x_auth_username = ''; } } } if (isset($this->_provider->x_auth_password)) { $x_auth_password = $this->_provider->x_auth_password; } else { if (isset($_POST['x_auth_password'])) { $x_auth_password = $_POST['x_auth_password']; } else { if (isset($_GET['x_auth_password'])) { $x_auth_password = $_GET['x_auth_password']; } else { $x_auth_password = ''; } } } if ($x_auth_mode != 'client_auth') { $this->_response->setResponseProvides('application/x-www-form-urlencoded,text/html;q=0.9'); $this->_response->setErrorMessage('oauth_problem=permission_denied', 400, 'Bad Request'); return; } $match = \Hubzero\User\Password::passwordMatches($x_auth_username, $x_auth_password, true); if (!$match) { $this->_response->setResponseProvides('application/x-www-form-urlencoded,text/html;q=0.9'); $this->_response->setErrorMessage('oauth_problem=permission_denied', 401, 'Unauthorized'); return; } $useraccount = User::getInstance(JUserHelper::getUserId($x_auth_username)); $db = App::get('db'); $db->setQuery("SELECT token,token_secret FROM #__oauthp_tokens WHERE consumer_id=" . $db->Quote($this->_provider->getConsumerData()->id) . " AND user_id =" . $db->Quote($useraccount->get('id')) . " LIMIT 1;"); $result = $db->loadObject(); if ($result === false) { $this->_response->setErrorMessage(500, 'Internal Server Error'); return; } if (!is_object($result)) { if ($this->_provider->getConsumerData()->xauth_grant < 1) { $this->_response->setErrorMessage(501, 'Internal Server Error'); return; } $token = sha1(OAuthProvider::generateToken(20, false)); $token_secret = sha1(OAuthProvider::generateToken(20, false)); $db = App::get('db'); $db->setQuery("INSERT INTO #__oauthp_tokens (consumer_id,user_id,state,token,token_secret,callback_url) VALUE (" . $db->Quote($this->_provider->getConsumerData()->id) . "," . $db->Quote($useraccount->get('id')) . "," . "'1'," . $db->Quote($token) . "," . $db->Quote($token_secret) . "," . $db->Quote($this->_provider->getConsumerData()->callback_url) . ");"); if (!$db->query()) { $this->_response->setErrorMessage(502, 'Internal Server Error'); return; } if ($db->getAffectedRows() < 1) { $this->_response->setErrorMessage(503, 'Internal Server Error'); return; } $this->_response->setResponseProvides('application/x-www-form-urlencoded,text/html;q=0.9'); $this->_response->setMessage("oauth_token=" . $token . "&oauth_token_secret=" . $token_secret, 200, "OK"); } else { $this->_response->setResponseProvides('application/x-www-form-urlencoded,text/html;q=0.9'); $this->_response->setMessage("oauth_token=" . $result->token . "&oauth_token_secret=" . $result->token_secret, 200, "OK"); } return; } else { $this->_response->setErrorMessage(503, 'Internal Server Error'); return; // @FIXME: we don't support 3-legged auth yet // lookup request token to access token, give out access token // check verifier // check used flag $this->_response->setResponseProvides('application/x-www-form-urlencoded,text/html;q=0.9'); $this->_response->setMessage("oauth_token=" . $token . "&oauth_token_secret=" . $token_secret, 200, "OK"); return; } }
/** * Show a form for changing user password * * @return void */ public function changepasswordTask() { // Check if they're logged in if (User::isGuest()) { $rtrn = Request::getVar('REQUEST_URI', Route::url('index.php?option=' . $this->_controller . '&task=changepassword', false, true), 'server'); App::redirect(Route::url('index.php?option=com_users&view=login&return=' . base64_encode($rtrn), false)); } // Incoming $id = Request::getInt('id', 0); $id = $id ?: User::get('id'); // Ensure we have an ID if (!$id) { App::abort(404, Lang::txt('COM_MEMBERS_NO_ID')); } // Check authorization if (!User::authorise('core.manage', $this->_option) && User::get('id') != $id) { App::abort(403, Lang::txt('MEMBERS_NOT_AUTH')); } // Initiate profile class $profile = Member::oneOrFail($id); // Ensure we have a member if (!$profile->get('id')) { App::abort(404, Lang::txt('COM_MEMBERS_NOT_FOUND')); } // Set the page title $title = Lang::txt(strtoupper($this->_option)); $title .= $this->_task ? ': ' . Lang::txt(strtoupper($this->_option . '_' . $this->_task)) : ''; Document::setTitle($title); // Set the pathway if (Pathway::count() <= 0) { Pathway::append(Lang::txt(strtoupper($this->_option)), 'index.php?option=' . $this->_option); } Pathway::append(stripslashes($profile->get('name')), 'index.php?option=' . $this->_option . '&id=' . $profile->get('id')); Pathway::append(Lang::txt('COM_MEMBERS_' . strtoupper($this->_task)), 'index.php?option=' . $this->_option . '&id=' . $profile->get('id') . '&task=' . $this->_task); // Load some needed libraries if (\Hubzero\User\Helper::isXDomainUser(User::get('id'))) { App::abort(403, Lang::txt('COM_MEMBERS_PASS_CHANGE_LINKED_ACCOUNT')); } // Incoming data $change = Request::getVar('change', '', 'post'); $oldpass = Request::getVar('oldpass', '', 'post'); $newpass = Request::getVar('newpass', '', 'post'); $newpass2 = Request::getVar('newpass2', '', 'post'); $message = Request::getVar('message', ''); if (!empty($message)) { $this->setError($message); } $this->view->title = $title; $this->view->profile = $profile; $this->view->change = $change; $this->view->oldpass = $oldpass; $this->view->newpass = $newpass; $this->view->newpass2 = $newpass2; $this->view->validated = true; $password_rules = \Hubzero\Password\Rule::all()->whereEquals('enabled', 1)->rows(); $this->view->password_rules = array(); foreach ($password_rules as $rule) { if (!empty($rule['description'])) { $this->view->password_rules[] = $rule['description']; } } if (!empty($newpass)) { $msg = \Hubzero\Password\Rule::verify($newpass, $password_rules, $profile->get('username')); } else { $msg = array(); } // Blank form request (no data submitted) if (empty($change)) { $this->view->setErrors($this->getErrors())->display(); return; } $passrules = false; if (!\Hubzero\User\Password::passwordMatches($profile->get('id'), $oldpass, true)) { $this->setError(Lang::txt('COM_MEMBERS_PASS_INCORRECT')); } elseif (!$newpass || !$newpass2) { $this->setError(Lang::txt('COM_MEMBERS_PASS_MUST_BE_ENTERED_TWICE')); } elseif ($newpass != $newpass2) { $this->setError(Lang::txt('COM_MEMBERS_PASS_NEW_CONFIRMATION_MISMATCH')); } elseif ($oldpass == $newpass) { // make sure the current password and new password are not the same // this should really be done in the password rules validation step $this->setError(Lang::txt('Your new password must be different from your current password')); } elseif (!empty($msg)) { $this->setError(Lang::txt('Password does not meet site password requirements. Please choose a password meeting all the requirements listed below.')); $this->view->set('validated', $msg); $passrules = true; } if ($this->getError()) { $change = array(); $change['_missing']['password'] = $this->getError(); if (!empty($msg) && $passrules) { $change['_missing']['password'] .= '<ul>'; foreach ($msg as $m) { $change['_missing']['password'] .= '<li>'; $change['_missing']['password'] .= $m; $change['_missing']['password'] .= '</li>'; } $change['_missing']['password'] .= '</ul>'; } if (Request::getInt('no_html', 0)) { echo json_encode($change); exit; } else { $this->view->setError($this->getError())->display(); return; } } // Encrypt the password and update the profile $result = \Hubzero\User\Password::changePassword($profile->get('id'), $newpass); // Save the changes if (!$result) { $this->view->setError(Lang::txt('MEMBERS_PASS_CHANGE_FAILED'))->display(); return; } // Redirect user back to main account page $return = base64_decode(Request::getVar('return', '', 'method', 'base64')); $this->_redirect = $return ? $return : Route::url('index.php?option=' . $this->_option . '&id=' . $id); $session = App::get('session'); // Redirect user back to main account page if (Request::getInt('no_html', 0)) { if ($session->get('badpassword', '0') || $session->get('expiredpassword', '0')) { $session->set('badpassword', '0'); $session->set('expiredpassword', '0'); } echo json_encode(array("success" => true)); exit; } else { if ($session->get('badpassword', '0') || $session->get('expiredpassword', '0')) { $session->set('badpassword', '0'); $session->set('expiredpassword', '0'); } } }