You are here

public function UserPasswordResetTest::testResetImpersonation in Drupal 9

Same name and namespace in other branches
  1. 8 core/modules/user/tests/src/Functional/UserPasswordResetTest.php \Drupal\Tests\user\Functional\UserPasswordResetTest::testResetImpersonation()
  2. 10 core/modules/user/tests/src/Functional/UserPasswordResetTest.php \Drupal\Tests\user\Functional\UserPasswordResetTest::testResetImpersonation()

Make sure that users cannot forge password reset URLs of other users.

File

core/modules/user/tests/src/Functional/UserPasswordResetTest.php, line 526

Class

UserPasswordResetTest
Ensure that password reset methods work as expected.

Namespace

Drupal\Tests\user\Functional

Code

public function testResetImpersonation() {

  // Create two identical user accounts except for the user name. They must
  // have the same empty password, so we can't use $this->drupalCreateUser().
  $edit = [];
  $edit['name'] = $this
    ->randomMachineName();
  $edit['mail'] = $edit['name'] . '@example.com';
  $edit['status'] = 1;
  $user1 = User::create($edit);
  $user1
    ->save();
  $edit['name'] = $this
    ->randomMachineName();
  $user2 = User::create($edit);
  $user2
    ->save();

  // Unique password hashes are automatically generated, the only way to
  // change that is to update it directly in the database.
  Database::getConnection()
    ->update('users_field_data')
    ->fields([
    'pass' => NULL,
  ])
    ->condition('uid', [
    $user1
      ->id(),
    $user2
      ->id(),
  ], 'IN')
    ->execute();
  \Drupal::entityTypeManager()
    ->getStorage('user')
    ->resetCache();
  $user1 = User::load($user1
    ->id());
  $user2 = User::load($user2
    ->id());
  $this
    ->assertEquals($user2
    ->getPassword(), $user1
    ->getPassword(), 'Both users have the same password hash.');

  // The password reset URL must not be valid for the second user when only
  // the user ID is changed in the URL.
  $reset_url = user_pass_reset_url($user1);
  $attack_reset_url = str_replace("user/reset/{$user1->id()}", "user/reset/{$user2->id()}", $reset_url);
  $this
    ->drupalGet($attack_reset_url);
  $this
    ->submitForm([], 'Log in');

  // Verify that the invalid password reset page does not show the user name.
  $this
    ->assertSession()
    ->pageTextNotContains($user2
    ->getAccountName());
  $this
    ->assertSession()
    ->addressEquals('user/password');
  $this
    ->assertSession()
    ->pageTextContains('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.');
}