diff --git a/core/modules/user/src/Controller/UserController.php b/core/modules/user/src/Controller/UserController.php index 779cf90..fbd3e1c 100644 --- a/core/modules/user/src/Controller/UserController.php +++ b/core/modules/user/src/Controller/UserController.php @@ -186,6 +186,8 @@ public function getResetPassForm(Request $request, $uid) { /** * Validates user, hash, and timestamp; logs the user in if correct. * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. * @param int $uid * User ID of the user requesting reset. * @param int $timestamp @@ -201,7 +203,7 @@ public function getResetPassForm(Request $request, $uid) { * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * If $uid is for a blocked user or invalid user ID. */ - public function resetPassLogin($uid, $timestamp, $hash) { + public function resetPassLogin(Request $request, $uid, $timestamp, $hash) { // The current user is not logged in, so check the parameters. $current = REQUEST_TIME; /** @var \Drupal\user\UserInterface $user */ @@ -222,6 +224,20 @@ public function resetPassLogin($uid, $timestamp, $hash) { return $this->redirect('user.pass'); } elseif ($user->isAuthenticated() && ($timestamp >= $user->getLastLoginTime()) && ($timestamp <= $current) && Crypt::hashEquals($hash, user_pass_rehash($user, $timestamp))) { + $flood_config = $this->config('user.flood'); + if ($flood_config->get('uid_only')) { + // Register flood events based on the uid only, so they apply for any + // IP address. This is the most secure option. + $identifier = $user->id(); + } + else { + // The default identifier is a combination of uid and IP address. This + // is less secure but more resistant to denial-of-service attacks that + // could lock out all users with public user names. + $identifier = $user->id() . '-' . $request->getClientIP(); + } + \Drupal::flood()->clear('user.failed_login_ip'); + \Drupal::flood()->clear('user.failed_login_user', $identifier); user_login_finalize($user); $this->logger->notice('User %name used one-time login link at time %timestamp.', ['%name' => $user->getDisplayName(), '%timestamp' => $timestamp]); drupal_set_message($this->t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.')); diff --git a/core/modules/user/src/Tests/UserLoginTest.php b/core/modules/user/src/Tests/UserLoginTest.php index af00c74..46a5c99 100644 --- a/core/modules/user/src/Tests/UserLoginTest.php +++ b/core/modules/user/src/Tests/UserLoginTest.php @@ -63,6 +63,11 @@ function testGlobalLoginFloodControl() { // A login with the correct password should also result in a flood error // message. $this->assertFailedLogin($user1, 'ip'); + $this->resetUserPassword($user1); + $this->drupalLogout(); + // Try to login as user 1, it should be successful. + $this->drupalLogin($user1); + $this->assertNoRaw(t('Too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or request a new password.', array(':url' => \Drupal::url('user.pass')))); } /** @@ -103,6 +108,11 @@ function testPerUserLoginFloodControl() { // Try one more attempt for user 1, it should be rejected, even if the // correct password has been used. $this->assertFailedLogin($user1, 'user'); + $this->resetUserPassword($user1); + $this->drupalLogout(); + // Try to login as user 1, it should be successful. + $this->drupalLogin($user1); + $this->assertNoRaw(\Drupal::translation()->formatPlural($this->config('user.flood')->get('user_limit'), 'There has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or request a new password.', 'There have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or request a new password.', array(':url' => \Drupal::url('user.pass')))); } /** @@ -175,4 +185,23 @@ function assertFailedLogin($account, $flood_trigger = NULL) { } } + /** + * Reset user password. + * + * @param object $user + * A user object. + */ + public function resetUserPassword($user) { + $this->drupalGet('user/password'); + $edit['name'] = $user->getUsername(); + $this->drupalPostForm(NULL, $edit, t('Submit')); + $_emails = $this->drupalGetMails(); + $email = end($_emails); + $urls = array(); + preg_match('#.+user/reset/.+#', $email['body'], $urls); + $resetURL = $urls[0]; + $this->drupalGet($resetURL); + $this->drupalPostForm(NULL, NULL, t('Log in')); + } + } diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml index e1bbbc7..23f6483 100644 --- a/sites/default/default.services.yml +++ b/sites/default/default.services.yml @@ -153,22 +153,3 @@ parameters: - sftp - webcal - rtsp - - # Configure Cross-Site HTTP requests (CORS). - # Read https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS - # for more information about the topic in general. - # Note: By default the configuration is disabled. - cors.config: - enabled: false - # Specify allowed headers, like 'x-allowed-header'. - allowedHeaders: [] - # Specify allowed request methods, specify ['*'] to allow all possible ones. - allowedMethods: [] - # Configure requests allowed from specific origins. - allowedOrigins: ['*'] - # Sets the Access-Control-Expose-Headers header. - exposedHeaders: false - # Sets the Access-Control-Max-Age header. - maxAge: false - # Sets the Access-Control-Allow-Credentials header. - supportsCredentials: false diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 9ee7360..7f28c29 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -144,11 +144,6 @@ * @code * 'prefix' => 'main_', * @endcode - * - * Per-table prefixes are deprecated as of Drupal 8.2, and will be removed in - * Drupal 9.0. After that, only a single prefix for all tables will be - * supported. - * * To provide prefixes for specific tables, set 'prefix' as an array. * The array's keys are the table names and the values are the prefixes. * The 'default' element is mandatory and holds the prefix for any tables @@ -330,6 +325,9 @@ * * You can also define an array of host names that can be accessed directly, * bypassing the proxy, in $settings['http_client_config']['proxy']['no']. + * + * If these settings are not configured, the system environment variables + * HTTP_PROXY, HTTPS_PROXY, and NO_PROXY on the web server will be used instead. */ # $settings['http_client_config']['proxy']['http'] = 'http://proxy_user:proxy_pass@example.com:8080'; # $settings['http_client_config']['proxy']['https'] = 'http://proxy_user:proxy_pass@example.com:8080'; @@ -422,20 +420,6 @@ */ # $settings['omit_vary_cookie'] = TRUE; - -/** - * Cache TTL for client error (4xx) responses. - * - * Items cached per-URL tend to result in a large number of cache items, and - * this can be problematic on 404 pages which by their nature are unbounded. A - * fixed TTL can be set for these items, defaulting to one hour, so that cache - * backends which do not support LRU can purge older entries. To disable caching - * of client error responses set the value to 0. Currently applies only to - * page_cache module. - */ -# $settings['cache_ttl_4xx'] = 3600; - - /** * Class Loader. * @@ -672,7 +656,7 @@ /** * Load services definition file. */ -$settings['container_yamls'][] = $app_root . '/' . $site_path . '/services.yml'; +$settings['container_yamls'][] = __DIR__ . '/services.yml'; /** * Override the default service container class. @@ -684,15 +668,6 @@ # $settings['container_base_class'] = '\Drupal\Core\DependencyInjection\Container'; /** - * Override the default yaml parser class. - * - * Provide a fully qualified class name here if you would like to provide an - * alternate implementation YAML parser. The class must implement the - * \Drupal\Component\Serialization\SerializationInterface interface. - */ -# $settings['yaml_parser_class'] = NULL; - -/** * Trusted host configuration. * * Drupal core can use the Symfony trusted host mechanism to prevent HTTP Host @@ -730,21 +705,6 @@ */ /** - * The default list of directories that will be ignored by Drupal's file API. - * - * By default ignore node_modules and bower_components folders to avoid issues - * with common frontend tools and recursive scanning of directories looking for - * extensions. - * - * @see file_scan_directory() - * @see \Drupal\Core\Extension\ExtensionDiscovery::scanDirectory() - */ -$settings['file_scan_ignore_directories'] = [ - 'node_modules', - 'bower_components', -]; - -/** * Load local development override configuration, if available. * * Use settings.local.php to override variables on secondary (staging, @@ -754,7 +714,6 @@ * * Keep this code block at the end of this file to take full effect. */ -# -# if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { -# include $app_root . '/' . $site_path . '/settings.local.php'; +# if (file_exists(__DIR__ . '/settings.local.php')) { +# include __DIR__ . '/settings.local.php'; # }