diff --git a/core/modules/user/src/Tests/UserEditTest.php b/core/modules/user/src/Tests/UserEditTest.php
index 46502f4..aaef855 100644
--- a/core/modules/user/src/Tests/UserEditTest.php
+++ b/core/modules/user/src/Tests/UserEditTest.php
@@ -102,4 +102,30 @@ function testUserWithoutEmailEdit() {
     $this->drupalPostForm("user/" . $user1->id() . "/edit", array('mail' => ''), t('Save'));
     $this->assertRaw(t("The changes have been saved."));
   }
+
+  /**
+   * Check that existing users whose username matches another user's email
+   * address or vice versa are not forced to update their username or email
+   * address.
+   */
+  function testUserEditWithConflicts() {
+    $user_with_email = $this->drupalCreateUser();
+    $user_with_name = $this->drupalCreateUser();
+
+    // Change the second user's username to the same value as the first user's
+    // email address.
+    $user_with_name->name = $user_with_email->mail;
+    $user_with_name->save();
+
+    // Test that the first user can save their account with no errors.
+    $this->drupalLogin($user_with_email);
+    $this->drupalPost("user/$user_with_email->uid/edit", array(), t('Save'));
+    $this->assertText(t("The changes have been saved."), "The user does not need to change their username if it matches another user's email address.");
+    $this->drupalLogout();
+
+    // Test that the second user can save their account with no errors.
+    $this->drupalLogin($user_with_name);
+    $this->drupalPost("user/$user_with_name->uid/edit", array(), t('Save'));
+    $this->assertText(t("The changes have been saved."), "The user does not need to change their email address if it matches another user's username.");
+  }
 }
diff --git a/core/modules/user/src/Tests/UserPasswordResetTest.php b/core/modules/user/src/Tests/UserPasswordResetTest.php
index 07c7fcf..66be438 100644
--- a/core/modules/user/src/Tests/UserPasswordResetTest.php
+++ b/core/modules/user/src/Tests/UserPasswordResetTest.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\user\Tests;
 
+use Drupal\Component\Utility\Crypt;
+use Drupal\Core\Site\Settings;
 use Drupal\system\Tests\Cache\PageCacheTagsTestBase;
 use Drupal\user\Entity\User;
 
@@ -70,6 +72,61 @@ protected function setUp() {
   }
 
   /**
+   * Attempts to reset a password when an email address matches two accounts.
+   */
+  function testUserPasswordResetDuplicateUsers() {
+    $user_settings = \Drupal::config('user.settings');
+    // Don't require email validation for new accounts.
+   $user_settings->set('verify_mail', FALSE);
+
+    // Don't require admin approval for new accounts.
+    $user_settings->set('register', USER_REGISTER_VISITORS);
+    $user_settings->save();
+    // Create two users.
+    $user_with_email = $this->drupalCreateUser();
+    $user_with_name = $this->drupalCreateUser();
+
+    // Change the second user's username to the same value as the first user's
+    // email address.
+   $user_with_name->name = $user_with_email->mail;
+    $user_with_name->save();
+
+    // Try and reset based on the duplicated email.
+    $edit = array();
+    $edit['name'] = $user_with_email->mail;
+    $this->drupalPost('user/password', $edit, t('E-mail new password'));
+    // There should be a field prompting the user to pick and account.
+    $this->assertField('choose_account', 'User is prompted to pick an account when email matches two accounts.');
+    // We should be sure to not expose another user's email to the user.
+    $this->assertNoText($user_with_name->mail, "Duplicated user's email is not exposed to the other user.");
+
+    // Select the account with the username matching the entered email.
+    $edit = array();
+    $edit['choose_account'] = Crypt::hashBase64(Settings::getHashSalt() . $user_with_email->uid);
+    $this->drupalPost(NULL, $edit, t('E-mail new password'));
+    $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'User is notified that password reset was sent.');
+
+    // Make sure that right user was sent a reset email.
+    $this->assertEqual(count($this->drupalGetMails(array('key' => 'password_reset', 'to' => $user_with_email->mail))), 1, 'The right user was sent a password reset mail.');
+    // Make sure that the other user was not sent an email.
+    $this->assertEqual(count($this->drupalGetMails(array('key' => 'password_reset', 'to' => $user_with_name->mail))), 0, 'The other user was not sent a password reset mail.');
+
+    // If the user is logged in, they should not have to choose an account to
+    // reset their password.
+    $this->drupalLogin($user_with_name);
+    $this->drupalGet('user/password');
+    // There should not be a form element for name.
+    $this->assertNoField('name', 'Duplicate user is not asked for a name when resetting password while logged in.');
+    $this->drupalPost(NULL, array(), t('E-mail new password'));
+    // Make sure the user with the matching username was sent an email.
+    $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'User is notified that password reset was sent when logged in.');
+    $this->assertEqual(count($this->drupalGetMails(array('key' => 'password_reset', 'to' => $user_with_name->mail))), 1, 'The right user was sent a password reset mail when logged in.');
+    // Make sure that the user with the matching email address was not sent an
+    // email. (An email was already sent to this user earlier.)
+    $this->assertEqual(count($this->drupalGetMails(array('key' => 'password_reset', 'to' => $user_with_email->mail))), 1, 'The other user was not sent a password reset mail when logged in.');
+  }
+
+  /**
    * Tests password reset functionality.
    */
   function testUserPasswordReset() {
diff --git a/core/modules/user/src/Tests/UserRegistrationTest.php b/core/modules/user/src/Tests/UserRegistrationTest.php
index cc5785a..7bcdcbc 100644
--- a/core/modules/user/src/Tests/UserRegistrationTest.php
+++ b/core/modules/user/src/Tests/UserRegistrationTest.php
@@ -150,6 +150,45 @@ function testRegistrationEmailDuplicates() {
     $this->assertText(t('The email address @email is already taken.', array('@email' => $duplicate_user->getEmail())), 'Supplying a duplicate email address with added whitespace displays an error message');
   }
 
+  /**
+   * Ensure that a new account cannot be created when the username matches an
+   * existing user's email address, or when the email address matches an
+   * existing user's username.
+   */
+  function testRegistrationConflicts() {
+    $user_settings = \Drupal::config('user.settings');
+    // Don't require email validation for new accounts.
+    $user_settings->set('verify_mail', FALSE);
+
+    // Don't require admin approval for new accounts.
+    $user_settings->set('register', USER_REGISTER_VISITORS);
+    $user_settings->save();
+
+    // Set up a user to check for duplicates.
+    $duplicate_user = $this->drupalCreateUser();
+
+    $edit = array();
+    $edit['name'] = $duplicate_user->mail;
+    $edit['mail'] = $this->randomMachineName() . '@example.com';
+
+    // Attempt to create a new account using a username that matches an
+    // existing email.
+    $this->drupalPost('user/register', $edit, t('Create new account'));
+    $this->assertText(t('The name @name is already taken.', array('@name' => $edit['name'])), "A user cannot be created when their username matches an existing user's email address.");
+
+    // Change the username to an email address.
+    $duplicate_user->name = $name = $this->randomMachineName() . '@example.com';
+    $duplicate_user->save();
+
+    $edit['name'] = $this->randomMachineName();
+    $edit['mail'] = $name;
+
+    // Attempt to create a new account using an email that matches an existing
+    // username.
+    $this->drupalPost('user/register', $edit, t('Create new account'));
+    $this->assertText(t('The e-mail address @email is already registered.', array('@email' => $edit['mail'])), "A user cannot be created when their email address matches an existing username.");
+  }
+
   function testRegistrationDefaultValues() {
     // Don't require email verification and allow registration by site visitors
     // without administrator approval.
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 1e6de88..a7c0551 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -18,6 +18,8 @@
 use Drupal\user\Entity\User;
 use Drupal\user\RoleInterface;
 use Drupal\user\UserInterface;
+use Drupal\Core\Language\LanguageInterface;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
 
 /**
  * @file
@@ -46,6 +48,238 @@
 const USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL = 'visitors_admin_approval';
 
 /**
+ * Form builder; Request a password reset.
+ *
+ * @ingroup forms
+ * @see user_pass_validate()
+ * @see user_pass_submit()
+ */
+function user_pass($form, FormStateInterface $form_state) {
+  global $user;
+
+  // When a user requests a password reset we check for username and email
+  // conflicts using a multistep form.
+  if (empty($form_state['step'])) {
+    $form_state['step'] = 1;
+  }
+
+  if ($form_state['step'] == 1) {
+    $form['name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Username or e-mail address'),
+      '#size' => 60,
+      '#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH),
+      '#required' => TRUE,
+      '#attributes' => array(
+        'autocorrect' => 'off',
+        'autocapitalize' => 'off',
+        'spellcheck' => 'false',
+        'autofocus' => 'autofocus',
+      ),
+    );
+    // Allow logged in users to request this also.
+    if ($user->uid > 0) {
+      $form['name']['#type'] = 'value';
+      $form['name']['#value'] = $user->mail;
+      $form['mail'] = array(
+        '#prefix' => '<p>',
+        '#markup' =>  t('Password reset instructions will be mailed to %email. You must log out to use the password reset link in the e-mail.', array('%email' => $user->mail)),
+        '#suffix' => '</p>',
+      );
+    }
+  }
+  else {
+    // Where there is a conflict between the username and email address for two
+    // users we supply both accounts as an option for the password reset.
+    $accounts = $form_state['storage']['accounts'];
+    $options = array();
+    foreach ($accounts as $account) {
+      $label = t('The account with the username: @name', array('@name' => $account->name));
+      if ($account->mail == $form_state['storage']['name']) {
+        $label = t('The account with the email address: @email', array('@email' => $account->mail));
+      }
+      $options[Crypt::hashBase64(Settings::getHashSalt() . $account->uid)] = $label;
+    }
+    $form['choose_account'] = array(
+      '#type' => 'radios',
+      '#title' => t('Choose account'),
+      '#required' => TRUE,
+      '#prefix' => "<p>" . t("There is a username conflict with the email address @email. Please select which account password to reset.", array('@email' => $form_state['storage']['name'])) . "</p>",
+      '#options' => $options,
+      '#default_value' => Crypt::hashBase64(Settings::getHashSalt() . reset($accounts)->uid),
+    );
+
+  }
+  $form['actions'] = array('#type' => 'actions');
+  if ($form_state['step'] == 2) {
+    $form['actions']['cancel'] = array(
+      '#type' => 'submit',
+      '#value' => t('Cancel'),
+      '#name' => 'cancel',
+      '#limit_validation_errors' => array(),
+      '#weight' => 5,
+    );
+  }
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('E-mail new password'),
+    '#name' => 'submit'
+  );
+
+  return $form;
+}
+
+function user_pass_validate($form, FormStateInterface $form_state) {
+  if ($form_state['step'] == 1) {
+    $name = trim($form_state['values']['name']);
+    $accounts = array();
+    // Try to load by email.
+    $users = entity_load_multiple_by_properties('user', array('mail' => $name, 'status' => '1'));
+    $account_by_email = reset($users);
+    if ($account_by_email) {
+      $accounts[Crypt::hashBase64(Settings::getHashSalt() . $account_by_email->uid)] = $account_by_email;
+    }
+    // Also try to load by user name, but only when the user is not logged in.
+    global $user;
+    if ($user->uid == 0) {
+      $users = entity_load_multiple_by_properties('user', array('name' => $name, 'status' => '1'));
+      $account_by_name = reset($users);
+      if ($account_by_name) {
+        $accounts[Crypt::hashBase64(Settings::getHashSalt() . $account_by_name->uid)] = $account_by_name;
+      }
+    }
+    if (!empty($accounts)) {
+      $form_state->setValue(array('#parents' => array('accounts')), $accounts);
+    }
+    else {
+      $form_state->setErrorByName('name', t('Sorry, %name is not recognized as a username or an e-mail address.', array('%name' => $name)));
+    }
+  }
+}
+
+function user_pass_submit($form, FormStateInterface $form_state) {
+  $language_interface = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_INTERFACE);
+
+  if ($form_state['step'] == 1) {
+    $accounts = $form_state['values']['accounts'];
+    if (count($accounts) > 1) {
+      $form_state['step'] = 2;
+      $form_state['storage']['name'] = $form_state->getValue('name');
+      $form_state['storage']['accounts'] = $accounts;
+      $form_state->setRebuild(TRUE);
+    }
+    else {
+      $account = reset($accounts);
+    }
+  }
+  else {
+    if ($form_state['triggering_element']['#name'] == 'submit') {
+      $chosen_account = $form_state->getValue('choose_account');
+      $account = $form_state['storage']['accounts'][$chosen_account];
+    }
+    else {
+      $form_state->setRedirectUrl('user/password');
+    }
+  }
+  if (isset($account)) {
+    // Mail one-time login URL and instructions using current language.
+    $mail = _user_mail_notify('password_reset', $account->getBCEntity(), $language_interface->id);
+    if (!empty($mail)) {
+      watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
+      drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
+    }
+
+    $form_state->setRedirectUrl('user');
+  }
+  return;
+}
+
+/**
+ * Menu callback; process one time login link and redirects to the user page on success.
+ *
+ * @deprecated Use \Drupal\user\Form\UserForm::resetPass()
+ */
+function user_pass_reset($form, $form_state, $uid, $timestamp, $hashed_pass, $action = NULL) {
+  global $user;
+
+  // When processing the one-time login link, we have to make sure that a user
+  // isn't already logged in.
+  if ($user->isAuthenticated()) {
+    // The existing user is already logged in.
+    if ($user->id() == $uid) {
+      drupal_set_message(t('You are logged in as %user. <a href="!user_edit">Change your password.</a>', array('%user' => $user->getUsername(), '!user_edit' => url("user/" . $user->id() . "/edit"))));
+    }
+    // A different user is already logged in on the computer.
+    else {
+      $reset_link_account = user_load($uid);
+      if (!empty($reset_link_account)) {
+        drupal_set_message(t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href="!logout">logout</a> and try using the link again.',
+          array('%other_user' => $user->getUsername(), '%resetting_user' => $reset_link_account->getUsername(), '!logout' => url('user/logout'))));
+      } else {
+        // Invalid one-time link specifies an unknown user.
+        drupal_set_message(t('The one-time login link you clicked is invalid.'));
+      }
+    }
+    return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
+  }
+  else {
+    // Time out, in seconds, until login URL expires.
+    $timeout = \Drupal::config('user.settings')->get('password_reset_timeout');
+    $current = REQUEST_TIME;
+    $account = user_load($uid);
+    // Verify that the user exists and is active.
+    if ($timestamp <= $current && $account && $account->isActive()) {
+      // No time out for first time login.
+      if ($account->getLastLoginTime() && $current - $timestamp > $timeout) {
+        drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
+        return new RedirectResponse(url('user/password', array('absolute' => TRUE)));
+      }
+      elseif ($account->isAuthenticated() && $timestamp >= $account->getLastLoginTime() && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->getPassword(), $timestamp, $account->getLastLoginTime())) {
+        // First stage is a confirmation form, then login
+        if ($action == 'login') {
+          // Set the new user.
+          // user_login_finalize() also updates the login timestamp of the
+          // user, which invalidates further use of the one-time login link.
+          user_login_finalize($account);
+          watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->getUsername(), '%timestamp' => $timestamp));
+          drupal_set_message(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.'));
+          // Let the user's password be changed without the current password check.
+          $token = Crypt::randomStringHashed(55);
+          $_SESSION['pass_reset_' . $user->id()] = $token;
+          return new RedirectResponse(url('user/' . $user->id() . '/edit', array(
+            'query' => array('pass-reset-token' => $token),
+            'absolute' => TRUE,
+          )));
+        }
+       else {
+          if (!$account->getLastLoginTime()) {
+            // No expiration for first time login.
+            $form['message'] = array('#markup' => t('<p>This is a one-time login for %user_name.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $account->getUsername())));
+          }
+          else {
+            $form['message'] = array('#markup' => t('<p>This is a one-time login for %user_name and will expire on %expiration_date.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $account->getUsername(), '%expiration_date' => format_date($timestamp + $timeout))));
+          }
+          $form['help'] = array('#markup' => '<p>' . t('This login can be used only once.') . '</p>');
+          $form['actions'] = array('#type' => 'actions');
+          $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
+          $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login");
+          return $form;
+        }
+      }
+      else {
+        drupal_set_message(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.'));
+        return new RedirectResponse(url('user/password', array('absolute' => TRUE)));
+      }
+    }
+    else {
+      // Deny access, no more clues.
+      // Everything will be in the watchdog's URL for the administrator to check.
+      throw new AccessDeniedHttpException();
+    }
+  }
+}
+
+/**
  * Implements hook_help().
  */
 function user_help($route_name, RouteMatchInterface $route_match) {
