/** * Logs a user in, using the local Craft user-base if possible, or falling back to legacy user-base data. * * @param string $username The user’s username. * @param string $password The user’s submitted password. * @param bool $rememberMe Whether the user should be remembered. * * @throws Exception * @return bool Whether the user was logged in successfully. */ public function login($username, $password, $rememberMe = false) { // First, try logging in a native User. $nativeSuccess = craft()->userSession->login($username, $password, $rememberMe); if ($nativeSuccess === true) { return LegacyLoginPlugin::NativeUserType; } // Okay, we'll try to match and validate a legacy user... // First, validate the provided username/password. $usernameModel = new UsernameModel(['username' => $username]); $passwordModel = new PasswordModel(['password' => $password]); if (!$usernameModel->validate() || !$passwordModel->validate()) { LegacyLoginPlugin::log($username . ' tried to log in unsuccessfully, but there was a validation issue with the username or password.', LogLevel::Warning); return false; } // Okay, we have a valid username and password... Can we authenticate a legacy user? $allowedServices = craft()->config->get('allowedServices', 'legacylogin'); // Bail if we're mis-configured if (!is_array($allowedServices)) { return false; } // Try each service in sequence... foreach ($allowedServices as $service) { switch ($service) { case LegacyLoginPlugin::BigCommerceLegacyUserType: if (LegacyLogin_BigCommerceHelper::login($username, $password, $rememberMe)) { return LegacyLoginPlugin::BigCommerceLegacyUserType; } break; case LegacyLoginPlugin::EE2LegacyUserType: if (LegacyLogin_Ee2Helper::login($username, $password, $rememberMe)) { return LegacyLoginPlugin::EE2LegacyUserType; } break; case LegacyLoginPlugin::WellspringLegacyUserType: if (LegacyLogin_WellspringHelper::login($username, $password, $rememberMe)) { return LegacyLoginPlugin::WellspringLegacyUserType; } break; case LegacyLoginPlugin::WordPressLegacyUserType: if (LegacyLogin_WordPressHelper::login($username, $password, $rememberMe)) { return LegacyLoginPlugin::WordPressLegacyUserType; } break; } } // Alas, it just wasn't meant to be. LegacyLoginPlugin::log($username . ' could not be authenticated as a legacy user.', LogLevel::Warning); return false; }
/** * Starts an elevated user session for the current user. * * @param string $password the current user’s password * * @return bool Whether the password was valid, and the user session has been elevated */ public function startElevatedSession($password) { // Get the current user $user = $this->getUser(); if (!$user) { return false; } // Validate the password $passwordModel = new PasswordModel(); $passwordModel->password = $password; if ($passwordModel->validate() && craft()->users->validatePassword($user->password, $password)) { // Set the elevated session expiration date $this->setState(self::ELEVATED_SESSION_TIMEOUT_VAR, time() + craft()->config->getElevatedSessionDuration()); return true; } return false; }
/** * Sets a user record up for a new password without saving it. * * @param UserModel $user The user who is getting a new password. * @param UserRecord $userRecord The user’s record. * @param bool $updatePasswordResetRequired Whether the user’s * {@link UserModel::passwordResetRequired passwordResetRequired} * attribute should be set `false`. Default is `true`. * @param bool $forceDifferentPassword Whether to force a new password to be different from any existing * password. * * @return bool */ private function _setPasswordOnUserRecord(UserModel $user, UserRecord $userRecord, $updatePasswordResetRequired = true, $forceDifferentPassword = false) { // Validate the password first $passwordModel = new PasswordModel(); $passwordModel->password = $user->newPassword; $validates = false; // If it's a new user AND we allow public registration, set it on the 'password' field and not 'newpassword'. if (!$user->id && craft()->systemSettings->getSetting('users', 'allowPublicRegistration')) { $passwordErrorField = 'password'; } else { $passwordErrorField = 'newPassword'; } if ($passwordModel->validate()) { if ($forceDifferentPassword) { // See if the passwords are the same. if (craft()->security->checkPassword($user->newPassword, $userRecord->password)) { $user->addErrors(array($passwordErrorField => Craft::t('That password is the same as your old password. Please choose a new one.'))); } else { $validates = true; } } else { $validates = true; } if ($validates) { // Fire an 'onBeforeSetPassword' event $event = new Event($this, array('password' => $user->newPassword, 'user' => $user)); $this->onBeforeSetPassword($event); // Is the event is giving us the go-ahead? $validates = $event->performAction; } } if ($validates) { $hash = craft()->security->hashPassword($user->newPassword); $userRecord->password = $user->password = $hash; $userRecord->invalidLoginWindowStart = null; $userRecord->invalidLoginCount = $user->invalidLoginCount = null; $userRecord->verificationCode = null; $userRecord->verificationCodeIssuedDate = null; // If it's an existing user, reset the passwordResetRequired bit. if ($updatePasswordResetRequired && $user->id) { $userRecord->passwordResetRequired = $user->passwordResetRequired = false; } $userRecord->lastPasswordChangeDate = $user->lastPasswordChangeDate = DateTimeHelper::currentUTCDateTime(); $user->newPassword = null; $success = true; } else { $user->addErrors(array($passwordErrorField => $passwordModel->getErrors('password'))); $success = false; } if ($success) { // Fire an 'onSetPassword' event $this->onSetPassword(new Event($this, array('user' => $user))); } return $success; }
/** * Logs a user in. * * If $rememberMe is set to `true`, the user will be logged in for the duration specified by the * [rememberedUserSessionDuration](http://buildwithcraft.com/docs/config-settings#rememberedUserSessionDuration) * config setting. Otherwise it will last for the duration specified by the * [userSessionDuration](http://buildwithcraft.com/docs/config-settings#userSessionDuration) * config setting. * * @param string $username The user’s username. * @param string $password The user’s submitted password. * @param bool $rememberMe Whether the user should be remembered. * * @throws Exception * @return bool Whether the user was logged in successfully. */ public function login($username, $password, $rememberMe = false) { // Validate the username/password first. $usernameModel = new UsernameModel(); $passwordModel = new PasswordModel(); $usernameModel->username = $username; $passwordModel->password = $password; // Require a userAgent string and an IP address to help prevent direct socket connections from trying to login. if (!craft()->request->userAgent || !$_SERVER['REMOTE_ADDR']) { Craft::log('Someone tried to login with loginName: ' . $username . ', without presenting an IP address or userAgent string.', LogLevel::Warning); $this->logout(true); $this->requireLogin(); } // Validate the model. if ($usernameModel->validate() && $passwordModel->validate()) { // Authenticate the credentials. $this->_identity = new UserIdentity($username, $password); $this->_identity->authenticate(); // Was the login successful? if ($this->_identity->errorCode == UserIdentity::ERROR_NONE) { // See if the 'rememberUsernameDuration' config item is set. If so, save the name to a cookie. $rememberUsernameDuration = craft()->config->get('rememberUsernameDuration'); if ($rememberUsernameDuration) { $this->saveCookie('username', $username, DateTimeHelper::timeFormatToSeconds($rememberUsernameDuration)); } else { // Just in case... $this->deleteStateCookie('username'); } // Get how long this session is supposed to last. $this->authTimeout = craft()->config->getUserSessionDuration($rememberMe); $id = $this->_identity->getId(); $states = $this->_identity->getPersistentStates(); // Fire an 'onBeforeLogin' event $this->onBeforeLogin(new Event($this, array('username' => $usernameModel->username))); // Run any before login logic. if ($this->beforeLogin($id, $states, false)) { $this->changeIdentity($id, $this->_identity->getName(), $states); // Fire an 'onLogin' event $this->onLogin(new Event($this, array('username' => $usernameModel->username))); if ($this->authTimeout) { if ($this->allowAutoLogin) { $user = craft()->users->getUserById($id); if ($user) { // Save the necessary info to the identity cookie. $sessionToken = StringHelper::UUID(); $hashedToken = craft()->security->hashData(base64_encode(serialize($sessionToken))); $uid = craft()->users->handleSuccessfulLogin($user, $hashedToken); $data = array($this->getName(), $sessionToken, $uid, $rememberMe ? 1 : 0, craft()->request->getUserAgent(), $this->saveIdentityStates()); $this->_identityCookie = $this->saveCookie('', $data, $this->authTimeout); } else { throw new Exception(Craft::t('Could not find a user with Id of {userId}.', array('{userId}' => $this->getId()))); } } else { throw new Exception(Craft::t('{class}.allowAutoLogin must be set true in order to use cookie-based authentication.', array('{class}' => get_class($this)))); } } $this->_sessionRestoredFromCookie = false; $this->_userRow = null; // Run any after login logic. $this->afterLogin(false); } return !$this->getIsGuest(); } } Craft::log($username . ' tried to log in unsuccessfully.', LogLevel::Warning); return false; }
/** * @param $userId * @param $user * @param $publicRegistration * @return bool */ private function _validateSensitiveFields($userId, UserModel $user, $publicRegistration) { $email = craft()->request->getPost('email'); $password = craft()->request->getPost('password'); // If this is an existing user if ($userId) { // If the user changed their email, make sure they have validated with their password. if ($email && $email != $user->email) { if ($password) { if ($this->_validateCurrentPassword($password)) { if (!$email) { $user->addError('email', Craft::t('Email address is required.')); } else { $user->email = $email; } } else { Craft::log('Tried to change password for userId: ' . $user->id . ', but the current password does not match what the user supplied.', LogLevel::Warning); $user->addError('currentPassword', Craft::t('Incorrect current password.')); } } else { Craft::log('Tried to change the email for userId: ' . $user->id . ', but the did not supply the existing password.', LogLevel::Warning); $user->addError('currentPassword', Craft::t('You must supply your existing password.')); } } } // If public registration is enabled, make sure it's a new user before we set the password. if ($publicRegistration && !$user->id && !craft()->request->isCpRequest()) { $password = (string) craft()->request->getPost('password'); // Validate the password. $passwordModel = new PasswordModel(); $passwordModel->password = $password; if ($passwordModel->validate()) { $user->password = $password; } else { $user->addError('password', $passwordModel->getError('password')); } } else { // Only an existing logged-in user or admins can change passwords. if (craft()->userSession->isAdmin() || $user->isCurrent()) { $newPassword = craft()->request->getPost('newPassword'); // Only actually validate/set it if these are not empty if ($newPassword && $password) { if ($this->_validateCurrentPassword($password)) { $newPasswordModel = new PasswordModel(); $newPasswordModel->password = $newPassword; if ($newPasswordModel->validate()) { $user->newPassword = (string) $newPassword; } else { $user->addError('newPassword', $newPasswordModel->getError('password')); } } else { $user->addError('currentPassword', Craft::t('Incorrect current password.')); Craft::log('Tried to change password for userId: ' . $user->id . ', but the current password does not match what the user supplied.', LogLevel::Warning); } } else { if ($newPassword && !$password) { $user->addError('currentPassword', Craft::t('You must supply your existing password.')); Craft::log('Tried to change password for userId: ' . $user->id . ', but the did not supply the existing password.', LogLevel::Warning); } } } } return !$user->hasErrors(); }
/** * Sets a user's password once they've verified they have access to their email. * * @throws HttpException|Exception * @return null */ public function actionSetPassword() { if (craft()->userSession->isLoggedIn()) { craft()->userSession->logout(); } $code = craft()->request->getRequiredParam('code'); $id = craft()->request->getRequiredParam('id'); $user = craft()->users->getUserByUid($id); if ($user) { $isCodeValid = craft()->users->isVerificationCodeValidForUser($user, $code); } if (!$user || !$isCodeValid) { throw new HttpException('200', Craft::t('Invalid verification code.')); } $url = craft()->config->getSetPasswordPath($code, $id, $user); if (craft()->request->isPostRequest()) { $newPassword = craft()->request->getRequiredPost('newPassword'); $passwordModel = new PasswordModel(); $passwordModel->password = $newPassword; if ($passwordModel->validate()) { $user->newPassword = $newPassword; if (craft()->users->changePassword($user)) { // Do we need to auto-login? if (craft()->config->get('autoLoginAfterAccountActivation') === true) { craft()->userSession->impersonate($user->id); } // If the user can't access the CP, then send them to the front-end setPasswordSuccessPath. if (!$user->can('accessCp')) { $setPasswordSuccessPath = craft()->config->getLocalized('setPasswordSuccessPath'); $url = UrlHelper::getSiteUrl($setPasswordSuccessPath); } else { $postCpLoginRedirect = craft()->config->get('postCpLoginRedirect'); $url = UrlHelper::getCpUrl($postCpLoginRedirect); } $this->redirect($url); } } craft()->userSession->setNotice(Craft::t('Couldn’t update password.')); $this->_processSetPasswordPath($user); $errors = array(); $errors = array_merge($errors, $user->getErrors('newPassword')); $errors = array_merge($errors, $passwordModel->getErrors('password')); $this->renderTemplate($url, array('errors' => $errors, 'code' => $code, 'id' => $id, 'newUser' => $user->password ? false : true)); } else { $this->_processSetPasswordPath($user); $this->renderTemplate($url, array('code' => $code, 'id' => $id, 'newUser' => $user->password ? false : true)); } }
/** * Logs a user in. * * If $rememberMe is set to `true`, the user will be logged in for the duration specified by the * [rememberedUserSessionDuration](http://buildwithcraft.com/docs/config-settings#rememberedUserSessionDuration) * config setting. Otherwise it will last for the duration specified by the * [userSessionDuration](http://buildwithcraft.com/docs/config-settings#userSessionDuration) * config setting. * * @param string $username The user’s username. * @param string $password The user’s submitted password. * @param bool $rememberMe Whether the user should be remembered. * * @throws Exception * @return bool Whether the user was logged in successfully. */ public function login($username, $password, $rememberMe = false) { // Require a userAgent string and an IP address to help prevent direct socket connections from trying to login. if (!craft()->request->userAgent || !$_SERVER['REMOTE_ADDR']) { Craft::log('Someone tried to login with loginName: ' . $username . ', without presenting an IP address or userAgent string.', LogLevel::Warning); $this->logout(true); $this->requireLogin(); } // Validate the username/password first. $usernameModel = new UsernameModel(); $passwordModel = new PasswordModel(); $usernameModel->username = $username; $passwordModel->password = $password; // Validate the models. if ($usernameModel->validate() && $passwordModel->validate()) { $this->_identity = new UserIdentity($username, $password); // Did we authenticate? if ($this->_identity->authenticate()) { return $this->loginByUserId($this->_identity->getUserModel()->id, $rememberMe, true); } } Craft::log($username . ' tried to log in unsuccessfully.', LogLevel::Warning); return false; }
/** * Sets a user record up for a new password without saving it. * * @access private * @param UserModel $user * @param UserRecord $userRecord * @return bool */ private function _setPasswordOnUserRecord(UserModel $user, UserRecord $userRecord) { // Validate the password first $passwordModel = new PasswordModel(); $passwordModel->password = $user->newPassword; if ($passwordModel->validate()) { $hashAndType = craft()->security->hashString($user->newPassword); $userRecord->password = $user->password = $hashAndType['hash']; $userRecord->encType = $user->encType = $hashAndType['encType']; $userRecord->status = $user->status = UserStatus::Active; $userRecord->invalidLoginWindowStart = null; $userRecord->invalidLoginCount = $user->invalidLoginCount = null; $userRecord->verificationCode = null; $userRecord->verificationCodeIssuedDate = null; // If it's an existing user, reset the passwordResetRequired bit. if ($user->id) { $userRecord->passwordResetRequired = $user->passwordResetRequired = false; } $userRecord->lastPasswordChangeDate = $user->lastPasswordChangeDate = DateTimeHelper::currentUTCDateTime(); $user->newPassword = null; return true; } else { // If it's a new user AND we allow public registration, set it on the 'password' field and not 'newpassword'. if (!$user->id && craft()->systemSettings->getSetting('users', 'allowPublicRegistration', false)) { $user->addErrors(array('password' => $passwordModel->getErrors('password'))); } else { $user->addErrors(array('newPassword' => $passwordModel->getErrors('password'))); } return false; } }