This method tries to use PHP's built in {@link password_hash()} function and falls back to the default
implementation if that's not possible.
public hashPassword ( string $password ) : string | ||
$password | string | The plaintext password to hash. |
Результат | string | Returns a secure hash of {@link $password}. |
/** * Signin process that multiple authentication methods. * * @access public * @since 2.0.0 * @author Tim Gunter * * @param string $Method * @param array $Arg1 * @return string Rendered XHTML template. */ public function signIn($Method = false, $Arg1 = false) { if (!$this->Request->isPostBack()) { $this->checkOverride('SignIn', $this->target()); } Gdn::session()->ensureTransientKey(); $this->addJsFile('entry.js'); $this->setData('Title', t('Sign In')); $this->Form->addHidden('Target', $this->target()); $this->Form->addHidden('ClientHour', date('Y-m-d H:00')); // Use the server's current hour as a default. // Additional signin methods are set up with plugins. $Methods = array(); $this->setData('Methods', $Methods); $this->setData('FormUrl', url('entry/signin')); $this->fireEvent('SignIn'); if ($this->Form->isPostBack()) { $this->Form->validateRule('Email', 'ValidateRequired', sprintf(t('%s is required.'), t(UserModel::signinLabelCode()))); $this->Form->validateRule('Password', 'ValidateRequired'); if (!$this->Request->isAuthenticatedPostBack() && !c('Garden.Embed.Allow')) { $this->Form->addError('Please try again.'); } // Check the user. if ($this->Form->errorCount() == 0) { $Email = $this->Form->getFormValue('Email'); $User = Gdn::userModel()->GetByEmail($Email); if (!$User) { $User = Gdn::userModel()->GetByUsername($Email); } if (!$User) { $this->Form->addError('@' . sprintf(t('User not found.'), strtolower(t(UserModel::SigninLabelCode())))); Logger::event('signin_failure', Logger::INFO, '{signin} failed to sign in. User not found.', array('signin' => $Email)); } else { // Check the password. $PasswordHash = new Gdn_PasswordHash(); $Password = $this->Form->getFormValue('Password'); try { $PasswordChecked = $PasswordHash->checkPassword($Password, val('Password', $User), val('HashMethod', $User)); // Rate limiting Gdn::userModel()->rateLimit($User, $PasswordChecked); if ($PasswordChecked) { // Update weak passwords $HashMethod = val('HashMethod', $User); if ($PasswordHash->Weak || $HashMethod && strcasecmp($HashMethod, 'Vanilla') != 0) { $Pw = $PasswordHash->hashPassword($Password); Gdn::userModel()->setField(val('UserID', $User), array('Password' => $Pw, 'HashMethod' => 'Vanilla')); } Gdn::session()->start(val('UserID', $User), true, (bool) $this->Form->getFormValue('RememberMe')); if (!Gdn::session()->checkPermission('Garden.SignIn.Allow')) { $this->Form->addError('ErrorPermission'); Gdn::session()->end(); } else { $ClientHour = $this->Form->getFormValue('ClientHour'); $HourOffset = Gdn::session()->User->HourOffset; if (is_numeric($ClientHour) && $ClientHour >= 0 && $ClientHour < 24) { $HourOffset = $ClientHour - date('G', time()); } if ($HourOffset != Gdn::session()->User->HourOffset) { Gdn::userModel()->setProperty(Gdn::session()->UserID, 'HourOffset', $HourOffset); } Gdn::userModel()->fireEvent('AfterSignIn'); $this->_setRedirect(); } } else { $this->Form->addError('Invalid password.'); Logger::event('signin_failure', Logger::WARNING, '{username} failed to sign in. Invalid password.', array('InsertName' => $User->Name)); } } catch (Gdn_UserException $Ex) { $this->Form->addError($Ex); } } } } else { if ($Target = $this->Request->get('Target')) { $this->Form->addHidden('Target', $Target); } $this->Form->setValue('RememberMe', true); } return $this->render(); }
/** * Do a password reset. * * @param int $UserID * @param string $Password * @return array|false Returns the user or **false** if the user doesn't exist. */ public function passwordReset($UserID, $Password) { // Encrypt the password before saving $PasswordHash = new Gdn_PasswordHash(); $Password = $PasswordHash->hashPassword($Password); $this->SQL->update('User')->set('Password', $Password)->set('HashMethod', 'Vanilla')->where('UserID', $UserID)->put(); $this->saveAttribute($UserID, 'PasswordResetKey', ''); $this->saveAttribute($UserID, 'PasswordResetExpires', ''); $this->EventArguments['UserID'] = $UserID; $this->fireEvent('AfterPasswordReset'); return $this->getID($UserID); }
/** * Generic save procedure. * * $Settings controls certain save functionality * * SaveRoles - Save 'RoleID' field as user's roles. Default false. * HashPassword - Hash the provided password on update. Default true. * FixUnique - Try to resolve conflicts with unique constraints on Name and Email. Default false. * ValidateEmail - Make sure the provided email addresses is formattted properly. Default true. * NoConfirmEmail - Disable email confirmation. Default false. * */ public function save($FormPostValues, $Settings = false) { // See if the user's related roles should be saved or not. $SaveRoles = val('SaveRoles', $Settings); // Define the primary key in this model's table. $this->defineSchema(); // Custom Rule: This will make sure that at least one role was selected if saving roles for this user. if ($SaveRoles) { $this->Validation->addRule('OneOrMoreArrayItemRequired', 'function:ValidateOneOrMoreArrayItemRequired'); // $this->Validation->AddValidationField('RoleID', $FormPostValues); $this->Validation->applyRule('RoleID', 'OneOrMoreArrayItemRequired'); } // Make sure that checkbox vals are saved as the appropriate value if (array_key_exists('ShowEmail', $FormPostValues)) { $FormPostValues['ShowEmail'] = ForceBool($FormPostValues['ShowEmail'], '0', '1', '0'); } if (array_key_exists('Banned', $FormPostValues)) { $FormPostValues['Banned'] = ForceBool($FormPostValues['Banned'], '0', '1', '0'); } if (array_key_exists('Confirmed', $FormPostValues)) { $FormPostValues['Confirmed'] = ForceBool($FormPostValues['Confirmed'], '0', '1', '0'); } unset($FormPostValues['Admin']); // Validate the form posted values if (array_key_exists('Gender', $FormPostValues)) { $FormPostValues['Gender'] = self::fixGender($FormPostValues['Gender']); } if (array_key_exists('DateOfBirth', $FormPostValues) && $FormPostValues['DateOfBirth'] == '0-00-00') { $FormPostValues['DateOfBirth'] = null; } $UserID = val('UserID', $FormPostValues); $User = array(); $Insert = $UserID > 0 ? false : true; if ($Insert) { $this->addInsertFields($FormPostValues); } else { $this->addUpdateFields($FormPostValues); $User = $this->getID($UserID, DATASET_TYPE_ARRAY); if (!$User) { $User = array(); } // Block banning the superadmin or System accounts if (val('Admin', $User) == 2 && val('Banned', $FormPostValues)) { $this->Validation->addValidationResult('Banned', 'You may not ban a System user.'); } elseif (val('Admin', $User) && val('Banned', $FormPostValues)) { $this->Validation->addValidationResult('Banned', 'You may not ban a user with the Admin flag set.'); } } $this->EventArguments['FormPostValues'] = $FormPostValues; $this->fireEvent('BeforeSaveValidation'); $RecordRoleChange = true; if ($UserID && val('FixUnique', $Settings)) { $UniqueValid = $this->validateUniqueFields(val('Name', $FormPostValues), val('Email', $FormPostValues), $UserID, true); if (!$UniqueValid['Name']) { unset($FormPostValues['Name']); } if (!$UniqueValid['Email']) { unset($FormPostValues['Email']); } $UniqueValid = true; } else { $UniqueValid = $this->validateUniqueFields(val('Name', $FormPostValues), val('Email', $FormPostValues), $UserID); } // Add & apply any extra validation rules: if (array_key_exists('Email', $FormPostValues) && val('ValidateEmail', $Settings, true)) { $this->Validation->applyRule('Email', 'Email'); } if ($this->validate($FormPostValues, $Insert) && $UniqueValid) { $Fields = $this->Validation->validationFields(); // All fields on the form that need to be validated (including non-schema field rules defined above) $RoleIDs = val('RoleID', $Fields, 0); $Username = val('Name', $Fields); $Email = val('Email', $Fields); $Fields = $this->Validation->schemaValidationFields(); // Only fields that are present in the schema // Remove the primary key from the fields collection before saving $Fields = removeKeyFromArray($Fields, $this->PrimaryKey); if (array_key_exists('AllIPAddresses', $Fields) && is_array($Fields['AllIPAddresses'])) { $Fields['AllIPAddresses'] = implode(',', $Fields['AllIPAddresses']); } if (!$Insert && array_key_exists('Password', $Fields) && val('HashPassword', $Settings, true)) { // Encrypt the password for saving only if it won't be hashed in _Insert() $PasswordHash = new Gdn_PasswordHash(); $Fields['Password'] = $PasswordHash->hashPassword($Fields['Password']); $Fields['HashMethod'] = 'Vanilla'; } // Check for email confirmation. if (self::requireConfirmEmail() && !val('NoConfirmEmail', $Settings)) { // Email address has changed if (isset($Fields['Email']) && (array_key_exists('Confirmed', $Fields) && $Fields['Confirmed'] == 0 || $UserID == Gdn::session()->UserID && $Fields['Email'] != Gdn::session()->User->Email && !Gdn::session()->checkPermission('Garden.Users.Edit'))) { $Attributes = val('Attributes', Gdn::session()->User); if (is_string($Attributes)) { $Attributes = @unserialize($Attributes); } $ConfirmEmailRoleID = RoleModel::getDefaultRoles(RoleModel::TYPE_UNCONFIRMED); if (!empty($ConfirmEmailRoleID)) { // The confirm email role is set and it exists so go ahead with the email confirmation. $NewKey = randomString(8); $EmailKey = touchValue('EmailKey', $Attributes, $NewKey); $Fields['Attributes'] = serialize($Attributes); $Fields['Confirmed'] = 0; } } } $this->EventArguments['SaveRoles'] =& $SaveRoles; $this->EventArguments['RoleIDs'] =& $RoleIDs; $this->EventArguments['Fields'] =& $Fields; $this->fireEvent('BeforeSave'); $User = array_merge($User, $Fields); // Check the validation results again in case something was added during the BeforeSave event. if (count($this->Validation->results()) == 0) { // If the primary key exists in the validated fields and it is a // numeric value greater than zero, update the related database row. if ($UserID > 0) { // If they are changing the username & email, make sure they aren't // already being used (by someone other than this user) if (ArrayValue('Name', $Fields, '') != '' || arrayValue('Email', $Fields, '') != '') { if (!$this->validateUniqueFields($Username, $Email, $UserID)) { return false; } } if (array_key_exists('Attributes', $Fields) && !is_string($Fields['Attributes'])) { $Fields['Attributes'] = serialize($Fields['Attributes']); } // Perform save DB operation $this->SQL->put($this->Name, $Fields, array($this->PrimaryKey => $UserID)); // Record activity if the person changed his/her photo. $Photo = arrayValue('Photo', $FormPostValues); if ($Photo !== false) { if (val('CheckExisting', $Settings)) { $User = $this->getID($UserID); $OldPhoto = val('Photo', $User); } if (isset($OldPhoto) && $OldPhoto != $Photo) { if (IsUrl($Photo)) { $PhotoUrl = $Photo; } else { $PhotoUrl = Gdn_Upload::url(changeBasename($Photo, 'n%s')); } $ActivityModel = new ActivityModel(); if ($UserID == Gdn::session()->UserID) { $HeadlineFormat = t('HeadlineFormat.PictureChange', '{RegardingUserID,You} changed {ActivityUserID,your} profile picture.'); } else { $HeadlineFormat = t('HeadlineFormat.PictureChange.ForUser', '{RegardingUserID,You} changed the profile picture for {ActivityUserID,user}.'); } $ActivityModel->save(array('ActivityUserID' => $UserID, 'RegardingUserID' => Gdn::session()->UserID, 'ActivityType' => 'PictureChange', 'HeadlineFormat' => $HeadlineFormat, 'Story' => img($PhotoUrl, array('alt' => t('Thumbnail'))))); } } } else { $RecordRoleChange = false; if (!$this->validateUniqueFields($Username, $Email)) { return false; } // Define the other required fields: $Fields['Email'] = $Email; $Fields['Roles'] = $RoleIDs; // Make sure that the user is assigned to one or more roles: $SaveRoles = false; // And insert the new user. $UserID = $this->_insert($Fields, $Settings); if ($UserID) { // Report that the user was created. $ActivityModel = new ActivityModel(); $ActivityModel->save(array('ActivityType' => 'Registration', 'ActivityUserID' => $UserID, 'HeadlineFormat' => t('HeadlineFormat.Registration', '{ActivityUserID,You} joined.'), 'Story' => t('Welcome Aboard!')), false, array('GroupBy' => 'ActivityTypeID')); // Report the creation for mods. $ActivityModel->save(array('ActivityType' => 'Registration', 'ActivityUserID' => Gdn::session()->UserID, 'RegardingUserID' => $UserID, 'NotifyUserID' => ActivityModel::NOTIFY_MODS, 'HeadlineFormat' => t('HeadlineFormat.AddUser', '{ActivityUserID,user} added an account for {RegardingUserID,user}.'))); } } // Now update the role settings if necessary. if ($SaveRoles) { // If no RoleIDs were provided, use the system defaults if (!is_array($RoleIDs)) { $RoleIDs = RoleModel::getDefaultRoles(RoleModel::TYPE_MEMBER); } $this->saveRoles($UserID, $RoleIDs, $RecordRoleChange); } // Send the confirmation email. if (isset($EmailKey)) { if (!is_array($User)) { $User = $this->getID($UserID, DATASET_TYPE_ARRAY); } $this->sendEmailConfirmationEmail($User, true); } $this->EventArguments['UserID'] = $UserID; $this->fireEvent('AfterSave'); } else { $UserID = false; } } else { $UserID = false; } // Clear cached user data if (!$Insert && $UserID) { $this->clearCache($UserID, array('user')); } return $UserID; }