protected function body() { if (!$this->isInputValid(['resetLink' => 'isNotEmpty', 'pass' => 'isNotEmpty'])) { return false; } $resetLink = $this->getParams('resetLink'); if (strlen($resetLink) < 1) { // We double-check here. This should not be necessary because the isInputValid function takes care of this. // However, if there is a bug in isInputValid that causes the check to be skipped, // this will allow the user to change the password of the first user with no resetLink active. // This could plausibly be the administrator. return $this->death(StringID::HackerError); } $encryptionType = Security::HASHTYPE_PHPASS; $newPassword = $this->getParams('pass'); $newPasswordHash = Security::hash($newPassword, $encryptionType); $usersWithThisResetLink = Repositories::getRepository(Repositories::User)->findBy(['resetLink' => $resetLink]); if (count($usersWithThisResetLink) !== 1) { return $this->death(StringID::ResetLinkDoesNotExist); } /** * @var $user \User */ $user = $usersWithThisResetLink[0]; if ($user->getResetLinkExpiry() < new \DateTime()) { return $this->death(StringID::ResetLinkExpired); } $user->setResetLink(''); $user->setPass($newPasswordHash); Repositories::persistAndFlush($user); return true; }
public function testCheck() { $this->assertTrue(Security::check("hello", "5d41402abc4b2a76b9719d911017c592", Security::HASHTYPE_MD5)); $this->assertTrue(Security::check("hi", "49f68a5c8493ec2c0bf489821c21fc3b", Security::HASHTYPE_MD5)); $this->assertTrue(Security::check("hello", '$2a$08$uHDGnFAtkAbBdH/iRt.jQOViR6bd2g3wwn6IS7MyvlMHoMvvBXDyi', Security::HASHTYPE_PHPASS)); $this->assertFalse(Security::check("hello2", "5d41402abc4b2a76b9719d911017c592", Security::HASHTYPE_MD5)); $this->assertFalse(Security::check("hello2", "hello2", Security::HASHTYPE_MD5)); $this->assertFalse(Security::check("hello2", "5d41402abc4b2a76b9719d911017c592", Security::HASHTYPE_PHPASS)); }
/** * Runs this script. * @return bool Is it successful? * @throws \Exception Should never occur. */ protected function body() { $inputs = array('name' => array('isAlphaNumeric', 'hasLength' => array('min_length' => Constants::UsernameMinLength, 'max_length' => Constants::UsernameMaxLength)), 'realname' => array('isNotEmpty', 'isName'), 'email' => 'isEmail', 'pass' => array(), 'repass' => array()); if (!$this->isInputValid($inputs)) { return false; } // Extract input data $username = strtolower($this->getParams('name')); $realname = $this->getParams('realname'); $email = $this->getParams('email'); $pass = $this->getParams('pass'); $repass = $this->getParams('repass'); $id = $this->getParams('id'); $type = $this->getParams('type'); $user = null; $isIdSet = $id !== null && $id !== ''; $isTypeSet = $type !== null && $type !== ''; // Extract database data if ($id) { $user = Repositories::findEntity(Repositories::User, $id); } $userExists = $user != null; $sameNameUserExists = count(Repositories::getRepository(Repositories::User)->findBy(['name' => $username])) > 0; // Custom verification of input data if ($pass !== $repass) { return $this->death(StringID::InvalidInput); } if ($userExists) { if ((strlen($pass) < Constants::PasswordMinLength || strlen($pass) > Constants::PasswordMaxLength) && $pass !== "") { return $this->death(StringID::InvalidInput); } } else { // A new user must have full password if (strlen($pass) < Constants::PasswordMinLength || strlen($pass) > Constants::PasswordMaxLength) { return $this->death(StringID::InvalidInput); } } $code = ''; $unhashedPass = $pass; $pass = Security::hash($pass, Security::HASHTYPE_PHPASS); $canAddUsers = User::instance()->hasPrivileges(User::usersAdd); $canEditUsers = User::instance()->hasPrivileges(User::usersManage); $isEditingSelf = $id == User::instance()->getId(); // This must not be a strict comparison. /** * @var $user \User */ if (!$userExists && !$sameNameUserExists) { if ($this->getParams('fromRegistrationForm')) { if ($type != Repositories::StudentUserType) { return $this->death(StringID::InsufficientPrivileges); } $code = md5(uniqid(mt_rand(), true)); $emailText = file_get_contents(Config::get("paths", "registrationEmail")); $emailText = str_replace("%{Username}", $username, $emailText); $emailText = str_replace("%{ActivationCode}", $code, $emailText); $emailText = str_replace("%{Link}", Config::getHttpRoot() . "#activate", $emailText); $lines = explode("\n", $emailText); $subject = $lines[0]; // The first line is subject. $text = preg_replace('/^.*\\n/', '', $emailText); // Everything except the first line. $returnCode = Core::sendEmail($email, $subject, $text); if (!$returnCode) { return $this->stop(ErrorCode::mail, 'user registration failed', 'email could not be sent'); } } else { if (!$canAddUsers) { return $this->death(StringID::InsufficientPrivileges); } } $user = new \User(); /** @var \UserType $typeEntity */ $typeEntity = Repositories::findEntity(Repositories::UserType, $type); $user->setType($typeEntity); $user->setPass($pass); $user->setName($username); $user->setEmail($email); $user->setActivationCode($code); $user->setEncryptionType(Security::HASHTYPE_PHPASS); $user->setRealName($realname); Repositories::persistAndFlush($user); } elseif ($isIdSet) { if (!$canEditUsers && ($isTypeSet || !$isEditingSelf)) { return $this->stop(ErrorCode::lowPrivileges, 'cannot edit data of users other than yourself'); } $type = $isTypeSet ? $type : $user->getType()->getId(); /** @var \UserType $typeEntity */ $typeEntity = Repositories::findEntity(Repositories::UserType, $type); if ($unhashedPass) { $user->setPass($pass); $user->setEncryptionType(Security::HASHTYPE_PHPASS); } $user->setType($typeEntity); $user->setEmail($email); $user->setActivationCode(''); $user->setRealName($realname); Repositories::persistAndFlush($user); } else { return $this->death(StringID::UserNameExists); } return true; }
/** * Tries to log user in with supplied credentials. * @param string $name username * @param string $pass password * @return bool true if login was successful */ public function login($name, $pass) { if ($this->data != null) { $this->logout(); } /// Username is case-insensitive. $name = strtolower($name); $users = Repositories::getRepository(Repositories::User)->findBy(['name' => $name]); if (!empty($users)) { /** * @var $user \User */ $user = $users[0]; if ($user->getActivationCode() !== '') { // Non-empty activation code means the account is not yet activated. return false; } $authenticationSuccess = Security::check($pass, $user->getPass(), $user->getEncryptionType()); if ($authenticationSuccess) { $this->data = array('id' => $user->getId(), 'name' => $user->getName(), 'privileges' => $user->getType()->getPrivileges(), 'realName' => $user->getRealName(), 'email' => $user->getEmail(), 'lastAccess' => $user->getLastAccess()->format("Y-m-d H:i:s"), 'applicationVersion' => implode('.', Config::get('version')), User::sendEmailOnAssignmentAvailableStudent => $user->getSendEmailOnNewAssignment() ? 1 : 0, User::sendEmailOnSubmissionConfirmedTutor => $user->getSendEmailOnNewSubmission() ? 1 : 0, User::sendEmailOnSubmissionRatedStudent => $user->getSendEmailOnSubmissionRated() ? 1 : 0); $this->refresh(); $user->setLastAccess(new \DateTime()); Repositories::persistAndFlush($user); $this->entity = $user; return true; } else { return false; } } return false; }