/** * @depends testLoginHistory */ public function testLoginHistoryPagination() { //Perform 20 more login $this->email = $this->valid_test_email; $this->password = $this->valid_test_password; $i = 1; while ($i <= 20) { $this->login(); $i++; } //Fetch paginated records (page 1) $loginHistory = (new User())->getLoginHistory($this->email, 1, 10); $properties = ['first', 'before', 'items', 'current', 'last', 'next', 'total_pages', 'total_items', 'limit']; $response = Utils::validateObjectHasAllProperties($properties, $loginHistory); $this->assertTrue($response); $this->assertEquals(10, count($loginHistory->items)); $this->assertEquals(1, $loginHistory->current); $this->assertEquals(1, $loginHistory->before); $this->assertEquals(2, $loginHistory->next); //fetch next set of records (page 2) $loginHistory = (new User())->getLoginHistory($this->email, 2, 10); $this->assertEquals(10, count($loginHistory->items)); $this->assertEquals(2, $loginHistory->current); $this->assertEquals(1, $loginHistory->before); //page 3 should be empty $loginHistory = (new User())->getLoginHistory($this->email, 3, 10); $this->assertEquals(0, count($loginHistory->items)); }
public function testLogin() { //login user without email and password. This should throw an invalid user exception $this->email = ""; $this->password = ""; $this->loginAndCatchAuthenticationException(); //set a valid email, and a wrong password $this->email = $this->valid_test_email; $this->password = '******'; $this->loginAndCatchAuthenticationException(); //set an invalid email, and a valid password $this->email = '*****@*****.**'; $this->password = $this->valid_test_password; $this->loginAndCatchAuthenticationException(); //Use valid credentials but an account that is inactive $this->email = $this->valid_test_email_2; $this->password = $this->valid_test_password; $this->loginAndCatchAuthenticationException(); //Use valid credentials and an account that is active $this->email = $this->valid_test_email; $this->password = $this->valid_test_password; $response = $this->login(); $this->assertNotEmpty($response, "Test Login Assertion: Valid email and valid password"); $this->assertEquals($this->sample_user_type_name, $response->UserType->name); $relationShips = ['PasswordChanges', 'PasswordResets', 'LoginHistory', 'UserType']; //check that all of the following relationships are valid foreach ($relationShips as $aRelationShip) { $response->{$aRelationShip}; } $requiredAttributes = ['id', 'email', 'password', 'status', 'created_at', 'updated_at', 'user_type_id']; $validate = Utils::validateObjectHasAllProperties($requiredAttributes, $response); $this->assertTrue($validate); }
public function testResetPassword() { $user = new User(); //generate a token that expires $token = $user->generateResetPasswordToken($this->valid_test_email); //throw an exception when an invalid token is used $wrongToken = Utils::generateRandomString(20); $this->throwResetPasswordException($wrongToken); //generate a token that expires using a negative timestamp so that the tokens expiry date is before the current time $expiredToken = $user->generateResetPasswordToken($this->valid_test_email, null, true, -(4 * 24 * 3600)); $this->throwResetPasswordException($expiredToken); //reset the password with a valid token $newPassword = User::generateRandomPassword(); $response = $user->resetPassword($this->valid_test_email, $newPassword, $token); $this->assertTrue($response); //authenticate with new password $response = $user->authenticate($this->valid_test_email, $newPassword); $this->assertNotEmpty($response); //try to use the same token again even when it has expired $this->throwResetPasswordException($token); }
/** * Test for user type/role creation */ public function testUserTypeCreation() { //Create a user type without a name (exception expected) $this->exception('', UserTypeException::class); //create two user types $admin = $this->createUserType('admin'); $this->assertNotEmpty($admin); $user = $this->createUserType('user'); $this->assertNotEmpty($user); //create another user type with the same name (exception expected) $this->exception('user', UserTypeException::class); //fetch all user types $userTypes = (new UserType())->getUserTypes(); $this->assertNotEmpty($userTypes); $this->assertEquals(2, count($userTypes->toArray())); $requiredProperties = ['id', 'name', 'created_at', 'updated_at']; foreach ($userTypes as $type) { $response = Utils::validateObjectHasAllProperties($requiredProperties, $type); $this->assertTrue($response); } }
/** * Set field before validation check */ public function beforeValidationOnCreate() { $this->date_logged = Utils::getCurrentDateTime(); }
/** * @param int $userId * @param string $newPassword * @param null $resetPasswordToken token to expire if call is from password reset * @return bool * @throws PasswordChangeException */ public function updatePassword($userId, $newPassword, $resetPasswordToken = null) { $transactionManager = new TransactionManager(); try { //use a transaction as we would be updating more than one table $transaction = $transactionManager->get(); $this->setTransaction($transaction); $user = User::findFirst($userId); if ($user == false) { $transaction->rollback(ErrorMessages::PASSWORD_UPDATE_FAILED); } $previousPassword = $user->password; $user->password = Utils::encryptPassword($newPassword); if (!$user->save()) { $transaction->rollback(ErrorMessages::PASSWORD_UPDATE_FAILED); } $userPasswordChange = new UserPasswordChange(); $userPasswordChange->setTransaction($transaction); $userPasswordChange->setDateChanged(date("Y-m-d H:i:s")); $userPasswordChange->setUserId($userId); $userPasswordChange->setPasswordHash($previousPassword); if (!$userPasswordChange->save()) { $transaction->rollback(ErrorMessages::PASSWORD_UPDATE_FAILED); } if (!empty($resetPasswordToken) && !(new UserPasswordReset())->expireToken($resetPasswordToken)) { $transaction->rollback(ErrorMessages::TOKEN_EXPIRY_FAILED); } $transaction->commit(); return true; } catch (TransactionFailed $e) { throw new PasswordChangeException($e->getMessage()); } }
/** * check if the new password does not correspond to the previous max passwords * We use max-1 in the query because we are assuming that the user's current password is * inclusive of the last max passwords used and this has already been checked above * * @param int $userId * @param string $newPassword * @param int $max * @throws PasswordChangeException */ public static function validateNewPassword($userId, $newPassword, $max = self::MAX_PASSWORD_CHANGES_BEFORE_REUSE) { $recentPasswords = UserPasswordChange::query()->where("user_id = :user_id:")->bind(["user_id" => $userId])->orderBy("date_changed DESC")->limit($max - 1)->execute()->toArray(); foreach ($recentPasswords as $aRecentPassword) { if (Utils::verifyPassword($newPassword, $aRecentPassword['password_hash'])) { throw new PasswordChangeException("You cannot use any of your last {$max} passwords"); } } }
public function __construct($message, $code = 0, Exception $previous = null) { $messages = Utils::getMessagesFromStringOrArray($message); // make sure everything is assigned properly parent::__construct($messages, $code, $previous); }
/** * @param int $user_id * @param int $tokenLength * @param int $expires * @param boolean $expiry * @return string * @throws ResetPasswordException */ public function generateToken($user_id, $tokenLength, $expires, $expiry) { if ($tokenLength > self::MAX_TOKEN_LENGTH) { throw new ResetPasswordException(sprintf(ErrorMessages::RESET_PASSWORD_TOKEN_TOO_LONG, UserPasswordReset::MAX_TOKEN_LENGTH)); } if ($tokenLength < self::MIN_TOKEN_LENGTH) { throw new ResetPasswordException(sprintf(ErrorMessages::RESET_PASSWORD_TOKEN_TOO_SHORT, UserPasswordReset::MIN_TOKEN_LENGTH)); } $tokenLength = $tokenLength - 10; //append a timestamp $token = Utils::generateRandomString($tokenLength, false); if ($this->tokenExists($token)) { return $this->generateToken($user_id, $tokenLength, $expires, $expiry); } $token = $token . time(); $this->setUserId($user_id); $this->setExpires((int) $expires); $this->setDateOfExpiry($expires ? time() + $expiry : null); $this->setToken($token); $this->setDateRequested(date("Y-m-d H:i:s")); if (!$this->create()) { throw new ResetPasswordException(ErrorMessages::RESET_PASSWORD_FAILED); } return $token; }
public function beforeValidationOnUpdate() { $this->updated_at = Utils::getCurrentDateTime(); }