UserPasswordResetTest.php 7.24 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
<?php

/**
 * @file
 * Definition of Drupal\user\Tests\UserPasswordResetTest.
 */

namespace Drupal\user\Tests;

use Drupal\simpletest\WebTestBase;

/**
13
14
15
 * Ensure that password reset methods work as expected.
 *
 * @group user
16
17
 */
class UserPasswordResetTest extends WebTestBase {
18
19
20
21
22
23
24
25
26
27
28
29

  /**
   * The profile to install as a basis for testing.
   *
   * This test uses the standard profile to test the password reset in
   * combination with an ajax request provided by the user picture configuration
   * in the standard profile.
   *
   * @var string
   */
  protected $profile = 'standard';

30
31
32
  /**
   * The user object to test password resetting.
   *
33
   * @var \Drupal\user\UserInterface
34
35
   */
  protected $account;
36

37
38
39
40
41
42
43
44
45
46
  /**
   * Modules to enable.
   *
   * @var array
   */
  public static $modules = ['block'];

  /**
   * {@inheritdoc}
   */
47
  protected function setUp() {
48
49
    parent::setUp();

50
51
    $this->drupalPlaceBlock('system_menu_block:account');

52
53
    // Create a user.
    $account = $this->drupalCreateUser();
54
55

    // Activate user by logging in.
56
    $this->drupalLogin($account);
57

58
    $this->account = user_load($account->id());
59
    $this->drupalLogout();
60
61
62
63

    // Set the last login time that is used to generate the one-time link so
    // that it is definitely over a second ago.
    $account->login = REQUEST_TIME - mt_rand(10, 100000);
64
    db_update('users_field_data')
65
      ->fields(array('login' => $account->getLastLoginTime()))
66
      ->condition('uid', $account->id())
67
      ->execute();
68
69
70
  }

  /**
71
   * Tests password reset functionality.
72
   */
73
74
75
76
  function testUserPasswordReset() {
    // Try to reset the password for an invalid account.
    $this->drupalGet('user/password');

77
    $edit = array('name' => $this->randomMachineName(32));
78
    $this->drupalPostForm(NULL, $edit, t('Submit'));
79

80
81
    $this->assertText(t('Sorry, @name is not recognized as a username or an email address.', array('@name' => $edit['name'])), 'Validation error message shown when trying to request password for invalid account.');
    $this->assertEqual(count($this->drupalGetMails(array('id' => 'user_password_reset'))), 0, 'No email was sent when requesting a password for an invalid account.');
82
83

    // Reset the password by username via the password reset page.
84
    $edit['name'] = $this->account->getUsername();
85
    $this->drupalPostForm(NULL, $edit, t('Submit'));
86

87
88
     // Verify that the user was sent an email.
    $this->assertMail('to', $this->account->getEmail(), 'Password email sent to user.');
89
    $subject = t('Replacement login information for @username at @site', array('@username' => $this->account->getUsername(), '@site' => $this->config('system.site')->get('name')));
90
    $this->assertMail('subject', $subject, 'Password reset email subject is correct.');
91
92
93
94
95

    $resetURL = $this->getResetURL();
    $this->drupalGet($resetURL);

    // Check the one-time login page.
96
    $this->assertText($this->account->getUsername(), 'One-time login page contains the correct username.');
97
    $this->assertText(t('This login can be used only once.'), 'Found warning about one-time login.');
98
    $this->assertTitle(t('Reset password | Drupal'), 'Page title is "Reset password".');
99
100

    // Check successful login.
101
    $this->drupalPostForm(NULL, NULL, t('Log in'));
102
    $this->assertLink(t('Log out'));
103
    $this->assertTitle(t('@name | @site', array('@name' => $this->account->getUsername(), '@site' => $this->config('system.site')->get('name'))), 'Logged in using password reset link.');
104

105
106
107
108
109
110
111
112
    // Make sure the ajax request from uploading a user picture does not
    // invalidate the reset token.
    $image = current($this->drupalGetTestFiles('image'));
    $edit = array(
      'files[user_picture_0]' => drupal_realpath($image->uri),
    );
    $this->drupalPostAjaxForm(NULL, $edit, 'user_picture_0_upload_button');

113
114
115
116
117
118
119
120
121
122
    // Change the forgotten password.
    $password = user_password();
    $edit = array('pass[pass1]' => $password, 'pass[pass2]' => $password);
    $this->drupalPostForm(NULL, $edit, t('Save'));
    $this->assertText(t('The changes have been saved.'), 'Forgotten password changed.');

    // Verify that the password reset session has been destroyed.
    $this->drupalPostForm(NULL, $edit, t('Save'));
    $this->assertText(t('Your current password is missing or incorrect; it\'s required to change the Password.'), 'Password needed to make profile changes.');

123
    // Log out, and try to log in again using the same one-time link.
124
    $this->drupalLogout();
125
126
127
    $this->drupalGet($resetURL);
    $this->assertText(t('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.'), 'One-time link is no longer valid.');

128
    // Request a new password again, this time using the email address.
129
130
131
    $this->drupalGet('user/password');
    // Count email messages before to compare with after.
    $before = count($this->drupalGetMails(array('id' => 'user_password_reset')));
132
    $edit = array('name' => $this->account->getEmail());
133
    $this->drupalPostForm(NULL, $edit, t('Submit'));
134
    $this->assertTrue( count($this->drupalGetMails(array('id' => 'user_password_reset'))) === $before + 1, 'Email sent when requesting password reset using email address.');
135

136
    // Create a password reset link as if the request time was 60 seconds older than the allowed limit.
137
    $timeout = $this->config('user.settings')->get('password_reset_timeout');
138
    $bogus_timestamp = REQUEST_TIME - $timeout - 60;
139
    $_uid = $this->account->id();
140
    $this->drupalGet("user/reset/$_uid/$bogus_timestamp/" . user_pass_rehash($this->account->getPassword(), $bogus_timestamp, $this->account->getLastLoginTime()));
141
    $this->assertText(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'Expired password reset request rejected.');
142
143
144
145
146
147
148

    // Create a user, block the account, and verify that a login link is denied.
    $timestamp = REQUEST_TIME - 1;
    $blocked_account = $this->drupalCreateUser()->block();
    $blocked_account->save();
    $this->drupalGet("user/reset/" . $blocked_account->id() . "/$timestamp/" . user_pass_rehash($blocked_account->getPassword(), $timestamp, $blocked_account->getLastLoginTime()));
    $this->assertResponse(403);
149
  }
150
151

  /**
152
   * Retrieves password reset email and extracts the login link.
153
154
155
156
157
158
159
160
161
162
   */
  public function getResetURL() {
    // Assume the most recent email.
    $_emails = $this->drupalGetMails();
    $email = end($_emails);
    $urls = array();
    preg_match('#.+user/reset/.+#', $email['body'], $urls);

    return $urls[0];
  }
163

164
165
166
  /**
   * Prefill the text box on incorrect login via link to password reset page.
   */
167
168
169
  public function testUserResetPasswordTextboxFilled() {
    $this->drupalGet('user/login');
    $edit = array(
170
171
      'name' => $this->randomMachineName(),
      'pass' => $this->randomMachineName(),
172
    );
173
    $this->drupalPostForm('user/login', $edit, t('Log in'));
174
    $this->assertRaw(t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>',
175
      array('@password' => \Drupal::url('user.pass', [], array('query' => array('name' => $edit['name']))))));
176
177
178
179
    unset($edit['pass']);
    $this->drupalGet('user/password', array('query' => array('name' => $edit['name'])));
    $this->assertFieldByName('name', $edit['name'], 'User name found.');
  }
180
}