reverted: --- b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php +++ a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php @@ -14,24 +14,6 @@ * Functional tests for user logins, including rate limiting of login attempts. */ class UserLoginTest extends WebTestBase { - - /** - * Modules to enable. - * - * @var array - */ - public static $modules = array('block'); - - /** - * User cases to use in tests. - * - * @var \Drupal\user\Plugin\Core\Entity\User - */ - protected $userCases; - - /** - * Implements getInfo(). - */ public static function getInfo() { return array( 'name' => 'User login', @@ -41,180 +23,98 @@ } /** - * Implements setUp(). - */ - public function setUp() { - parent::setUp(); - - // The maximum password length is 128 characters. - $password_lengths = array( - 128 => 'valid', - 129 => 'invalid', - ); - - foreach ($password_lengths as $password_length => $password_case) { - $test_name = $this->randomName(); - $test_pass = user_password($password_length); - - // Create the base user, based on drupalCreateUser(). - $account = entity_create('user', array( - 'name' => $test_name, - 'mail' => $test_name . '@example.com', - 'pass' => $test_pass, - 'status' => 1, - )); - $account->save(); - $account->pass_raw = $test_pass; - $this->userCases[$password_case] = $account; - } - } - - /** - * Test log in with long password on user/login. - */ - public function testPasswordLengthPage() { - $user_with_valid_password_length = clone $this->userCases['valid']; - $auth = array( - 'name' => $user_with_valid_password_length->name, - 'pass' => $user_with_valid_password_length->pass_raw, - ); - - $this->drupalPost('user/login', $auth, t('Log in')); - $this->assertNoText(t('User login'), 'Logged in with 128 character long password.'); - $this->assertPattern('!!', 'Redirected to /user'); - $this->drupalLogout(); - - $user_with_invalid_password_length = clone $this->userCases['invalid']; - $auth = array( - 'name' => $user_with_invalid_password_length->name, - 'pass' => $user_with_invalid_password_length->pass_raw, - ); - - $this->drupalPost('user/login', $auth, t('Log in')); - $this->assertText(t('Log in'), 'Could not log in with 129 character long password via user/login.'); - $this->assertText('Password cannot be longer than', 'Error message appeared.'); - } - - /** - * Test log in with long password on login block. - */ - public function testPasswordLengthBlock() { - $user_with_valid_password_length = clone $this->userCases['valid']; - $auth = array( - 'name' => $user_with_valid_password_length->name, - 'pass' => $user_with_valid_password_length->pass_raw, - ); - - $this->drupalPlaceBlock('user_login_block'); - $this->drupalPost('filter/tips', $auth, t('Log in')); - $this->assertNoText(t('User login'), 'Logged in.'); - $this->drupalLogout(); - - $user_with_invalid_password_length = clone $this->userCases['invalid']; - $auth = array( - 'name' => $user_with_invalid_password_length->name, - 'pass' => $user_with_invalid_password_length->pass_raw, - ); - - $this->drupalPost('filter/tips', $auth, t('Log in')); - $this->assertText(t('User login'), 'Could not log in with 129 character long password via login block.'); - $this->assertText('Password cannot be longer than', 'Error message appeared.'); - } - - /** * Test the global login flood control. */ + function testGlobalLoginFloodControl() { - public function testGlobalLoginFloodControl() { config('user.flood') ->set('ip_limit', 10) // Set a high per-user limit out so that it is not relevant in the test. ->set('user_limit', 4000) ->save(); + $user1 = $this->drupalCreateUser(array()); + $incorrect_user1 = clone $user1; + $incorrect_user1->pass_raw .= 'incorrect'; - $valid_user = clone $this->userCases['valid']; - $incorrect_user = clone $valid_user; - $incorrect_user->pass_raw .= 'incorrect'; // Try 2 failed logins. for ($i = 0; $i < 2; $i++) { + $this->assertFailedLogin($incorrect_user1); - $this->assertFailedLogin($incorrect_user); } // A successful login will not reset the IP-based flood control count. + $this->drupalLogin($user1); - $this->drupalLogin($valid_user); $this->drupalLogout(); // Try 8 more failed logins, they should not trigger the flood control // mechanism. for ($i = 0; $i < 8; $i++) { + $this->assertFailedLogin($incorrect_user1); - $this->assertFailedLogin($incorrect_user); } // The next login trial should result in an IP-based flood error message. + $this->assertFailedLogin($incorrect_user1, 'ip'); - $this->assertFailedLogin($incorrect_user, 'ip'); // A login with the correct password should also result in a flood error // message. + $this->assertFailedLogin($user1, 'ip'); - $this->assertFailedLogin($incorrect_user, 'ip'); } /** * Test the per-user login flood control. */ + function testPerUserLoginFloodControl() { - public function testPerUserLoginFloodControl() { config('user.flood') // Set a high global limit out so that it is not relevant in the test. ->set('ip_limit', 4000) ->set('user_limit', 3) ->save(); + $user1 = $this->drupalCreateUser(array()); + $incorrect_user1 = clone $user1; + $incorrect_user1->pass_raw .= 'incorrect'; - $valid_user1 = clone $this->userCases['valid']; - $valid_user2 = $this->drupalCreateUser(array()); + $user2 = $this->drupalCreateUser(array()); - $incorrect_user = clone $valid_user1; - $incorrect_user->pass_raw .= 'incorrect'; // Try 2 failed logins. for ($i = 0; $i < 2; $i++) { + $this->assertFailedLogin($incorrect_user1); - $this->assertFailedLogin($incorrect_user); } // A successful login will reset the per-user flood control count. + $this->drupalLogin($user1); - $this->drupalLogin($valid_user1); $this->drupalLogout(); // Try 3 failed logins for user 1, they will not trigger flood control. for ($i = 0; $i < 3; $i++) { + $this->assertFailedLogin($incorrect_user1); - $this->assertFailedLogin($incorrect_user); } // Try one successful attempt for user 2, it should not trigger any // flood control. + $this->drupalLogin($user2); - $this->drupalLogin($valid_user2); $this->drupalLogout(); // Try one more attempt for user 1, it should be rejected, even if the // correct password has been used. + $this->assertFailedLogin($user1, 'user'); - $this->assertFailedLogin($incorrect_user, 'user'); } /** * Test that user password is re-hashed upon login after changing $count_log2. */ + function testPasswordRehashOnLogin() { + // Determine default log2 for phpass hashing algoritm - public function testPasswordRehashOnLogin() { - // Determine default log2 for phpass hashing algoritm. $default_count_log2 = 16; + // Retrieve instance of password hashing algorithm - // Retrieve instance of password hashing algorithm. $password_hasher = drupal_container()->get('password'); // Create a new user and authenticate. + $account = $this->drupalCreateUser(array()); - $account = clone $this->userCases['valid']; $password = $account->pass_raw; $this->drupalLogin($account); $this->drupalLogout(); + // Load the stored user. The password hash should reflect $default_count_log2. - // Load the stored user. The password hash should reflect - // $default_count_log2. $account = user_load($account->uid); $this->assertIdentical($password_hasher->getCountLog2($account->pass), $default_count_log2); @@ -234,13 +134,13 @@ /** * Make an unsuccessful login attempt. * + * @param $account - * @param object $account * A user object with name and pass_raw attributes for the login attempt. + * @param $flood_trigger - * @param string $flood_trigger * Whether or not to expect that the flood control mechanism will be * triggered. */ + function assertFailedLogin($account, $flood_trigger = NULL) { - protected function assertFailedLogin($account, $flood_trigger = NULL) { $edit = array( 'name' => $account->name, 'pass' => $account->pass_raw, only in patch2: unchanged: --- a/core/modules/user/src/Tests/UserLoginTest.php +++ b/core/modules/user/src/Tests/UserLoginTest.php @@ -18,6 +18,49 @@ class UserLoginTest extends WebTestBase { /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('block'); + + /** + * User cases to use in tests. + * + * @var array + */ + protected $userCases; + + /** + * Implements setUp(). + */ + public function setUp() { + parent::setUp(); + + // The maximum password length is 128 characters. + $password_lengths = array( + 128 => 'valid', + 129 => 'invalid', + ); + + foreach ($password_lengths as $password_length => $password_case) { + $test_name = $this->randomMachineName(32); + $test_pass = user_password($password_length); + + // Create the base user, based on drupalCreateUser(). + $account = entity_create('user', array( + 'name' => $test_name, + 'mail' => $test_name . '@example.com', + 'pass' => $test_pass, + 'status' => 1, + )); + $account->save(); + $account->pass_raw = $test_pass; + $this->userCases[$password_case] = $account; + } + } + + /** * Tests login with destination. */ function testLoginCacheTagsAndDestination() { @@ -34,98 +77,155 @@ function testLoginCacheTagsAndDestination() { } /** + * Test log in with long password on user/login. + */ + public function testPasswordLengthPage() { + /** @var User $user_with_valid_password_length */ + $user_with_valid_password_length = clone $this->userCases['valid']; + $auth = array( + 'name' => $user_with_valid_password_length->getAccountName(), + 'pass' => $user_with_valid_password_length->pass_raw, + ); + + $this->drupalPostForm('user/login', $auth, t('Log in')); + $this->assertNoText(t('User login'), 'Logged in with 128 character long password.'); + $this->assertPattern('!!', 'Redirected to /user'); + $this->drupalLogout(); + + /** @var User $user_with_invalid_password_length */ + $user_with_invalid_password_length = clone $this->userCases['invalid']; + $auth = array( + 'name' => $user_with_invalid_password_length->getAccountName(), + 'pass' => $user_with_invalid_password_length->pass_raw, + ); + + $this->drupalPostForm('user/login', $auth, t('Log in')); + $this->assertTrue(strpos($this->getRawContent(), (string) t('Log in')) > 0, 'Could not log in with 129 character long password via user/login.'); + $this->assertText('Password cannot be longer than', 'Error message appeared.'); + } + + /** + * Test log in with long password on login block. + */ + public function testPasswordLengthBlock() { + /** @var User $user_with_valid_password_length */ + $user_with_valid_password_length = clone $this->userCases['valid']; + $auth = array( + 'name' => $user_with_valid_password_length->getAccountName(), + 'pass' => $user_with_valid_password_length->pass_raw, + ); + + $this->drupalPlaceBlock('user_login_block'); + $this->drupalPostForm('filter/tips', $auth, t('Log in')); + $this->assertNoText(t('User login'), 'Logged in.'); + $this->drupalLogout(); + + /** @var User $user_with_invalid_password_length */ + $user_with_invalid_password_length = clone $this->userCases['invalid']; + $auth = array( + 'name' => $user_with_invalid_password_length->getAccountName(), + 'pass' => $user_with_invalid_password_length->pass_raw, + ); + + $this->drupalPostForm('filter/tips', $auth, t('Log in')); + $this->assertTrue(strpos($this->getRawContent(), (string) t('Log in')) > 0, 'Could not log in with 129 character long password via login block.'); + $this->assertText('Password cannot be longer than', 'Error message appeared.'); + } + + /** * Test the global login flood control. */ - function testGlobalLoginFloodControl() { + public function testGlobalLoginFloodControl() { $this->config('user.flood') ->set('ip_limit', 10) // Set a high per-user limit out so that it is not relevant in the test. ->set('user_limit', 4000) ->save(); - $user1 = $this->drupalCreateUser(array()); - $incorrect_user1 = clone $user1; - $incorrect_user1->pass_raw .= 'incorrect'; + $valid_user = clone $this->userCases['valid']; + $incorrect_user = clone $valid_user; + $incorrect_user->pass_raw .= 'incorrect'; // Try 2 failed logins. for ($i = 0; $i < 2; $i++) { - $this->assertFailedLogin($incorrect_user1); + $this->assertFailedLogin($incorrect_user); } // A successful login will not reset the IP-based flood control count. - $this->drupalLogin($user1); + $this->drupalLogin($valid_user); $this->drupalLogout(); // Try 8 more failed logins, they should not trigger the flood control // mechanism. for ($i = 0; $i < 8; $i++) { - $this->assertFailedLogin($incorrect_user1); + $this->assertFailedLogin($incorrect_user); } // The next login trial should result in an IP-based flood error message. - $this->assertFailedLogin($incorrect_user1, 'ip'); + $this->assertFailedLogin($incorrect_user, 'ip'); // A login with the correct password should also result in a flood error // message. - $this->assertFailedLogin($user1, 'ip'); + $this->assertFailedLogin($incorrect_user, 'ip'); } /** * Test the per-user login flood control. */ - function testPerUserLoginFloodControl() { + public function testPerUserLoginFloodControl() { $this->config('user.flood') // Set a high global limit out so that it is not relevant in the test. ->set('ip_limit', 4000) ->set('user_limit', 3) ->save(); - $user1 = $this->drupalCreateUser(array()); - $incorrect_user1 = clone $user1; - $incorrect_user1->pass_raw .= 'incorrect'; + $valid_user1 = clone $this->userCases['valid']; + $valid_user2 = $this->drupalCreateUser(array()); - $user2 = $this->drupalCreateUser(array()); + $incorrect_user = clone $valid_user1; + $incorrect_user->pass_raw .= 'incorrect'; // Try 2 failed logins. for ($i = 0; $i < 2; $i++) { - $this->assertFailedLogin($incorrect_user1); + $this->assertFailedLogin($incorrect_user); } // A successful login will reset the per-user flood control count. - $this->drupalLogin($user1); + $this->drupalLogin($valid_user1); $this->drupalLogout(); // Try 3 failed logins for user 1, they will not trigger flood control. for ($i = 0; $i < 3; $i++) { - $this->assertFailedLogin($incorrect_user1); + $this->assertFailedLogin($incorrect_user); } // Try one successful attempt for user 2, it should not trigger any // flood control. - $this->drupalLogin($user2); + $this->drupalLogin($valid_user2); $this->drupalLogout(); // Try one more attempt for user 1, it should be rejected, even if the // correct password has been used. - $this->assertFailedLogin($user1, 'user'); + $this->assertFailedLogin($incorrect_user, 'user'); } /** * Test that user password is re-hashed upon login after changing $count_log2. */ - function testPasswordRehashOnLogin() { + public function testPasswordRehashOnLogin() { // Determine default log2 for phpass hashing algorithm $default_count_log2 = 16; - // Retrieve instance of password hashing algorithm + // Retrieve instance of password hashing algorithm. $password_hasher = $this->container->get('password'); // Create a new user and authenticate. - $account = $this->drupalCreateUser(array()); + $account = clone $this->userCases['valid']; $password = $account->pass_raw; $this->drupalLogin($account); $this->drupalLogout(); - // Load the stored user. The password hash should reflect $default_count_log2. + // Load the stored user. The password hash should reflect + // $default_count_log2. $user_storage = $this->container->get('entity.manager')->getStorage('user'); $account = User::load($account->id()); $this->assertIdentical($password_hasher->getCountLog2($account->getPassword()), $default_count_log2); @@ -159,7 +259,7 @@ function testPasswordRehashOnLogin() { * . * - Set to NULL to expect a failed login. */ - function assertFailedLogin($account, $flood_trigger = NULL) { + protected function assertFailedLogin($account, $flood_trigger = NULL) { $edit = array( 'name' => $account->getUsername(), 'pass' => $account->pass_raw,