diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index f7d4552..f87da98 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -292,6 +292,23 @@ function user_admin_settings() {
     '#description' => t('This role will be automatically assigned new permissions whenever a module is enabled. Changing this setting will not affect existing permissions.'),
   );
 
+  // User login settings.
+  $form['user_login'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('User login'),
+  );
+  $form['user_login']['user_login_name_option'] = array(
+    '#type' => 'select',
+    '#title' => t('Login credentials'),
+    '#description' => t('The details users may use to identify themselves.'),
+    '#options' => array(
+      USER_LOGIN_USERNAME_ONLY => t('Username'),
+      USER_LOGIN_EMAIL_ONLY => t('E-mail address'),
+      USER_LOGIN_USERNAME_OR_EMAIL => t('Username or e-mail address'),
+    ),
+    '#default_value' => variable_get('user_login_name_option', USER_LOGIN_USERNAME_ONLY),
+  );
+
   // User registration settings.
   $form['registration_cancellation'] = array(
     '#type' => 'fieldset',
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 009a716..035bb57 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -16,6 +16,21 @@ const USERNAME_MAX_LENGTH = 60;
 const EMAIL_MAX_LENGTH = 254;
 
 /**
+ * Users can login with username only.
+ */
+const USER_LOGIN_USERNAME_ONLY = 'username_only';
+
+/**
+ * Users can login with e-mail address only.
+ */
+const USER_LOGIN_EMAIL_ONLY = 'email_only';
+
+/**
+ * Users can login using either username or e-mail address.
+ */
+const USER_LOGIN_USERNAME_OR_EMAIL = 'username_or_email';
+
+/**
  * Only administrators can create user accounts.
  */
 const USER_REGISTER_ADMINISTRATORS_ONLY = 0;
@@ -1210,12 +1225,32 @@ function user_login_block($form) {
   $form['#id'] = 'user-login-form';
   $form['#validate'] = user_login_default_validators();
   $form['#submit'][] = 'user_login_submit';
-  $form['name'] = array('#type' => 'textfield',
-    '#title' => t('Username'),
-    '#maxlength' => USERNAME_MAX_LENGTH,
-    '#size' => 15,
-    '#required' => TRUE,
-  );
+  switch (variable_get('user_login_name_option', USER_LOGIN_USERNAME_ONLY)) {
+    case USER_LOGIN_USERNAME_ONLY:
+      $form['name'] = array('#type' => 'textfield',
+        '#title' => t('Username'),
+        '#maxlength' => USERNAME_MAX_LENGTH,
+        '#size' => 15,
+        '#required' => TRUE,
+      );
+      break;
+    case USER_LOGIN_EMAIL_ONLY:
+      $form['name'] = array('#type' => 'textfield',
+        '#title' => t('E-mail address'),
+        '#maxlength' => EMAIL_MAX_LENGTH,
+        '#size' => 15,
+        '#required' => TRUE,
+      );
+      break;
+    case USER_LOGIN_USERNAME_OR_EMAIL:
+      $form['name'] = array('#type' => 'textfield',
+        '#title' => t('Username or e-mail address'),
+        '#maxlength' => EMAIL_MAX_LENGTH,
+        '#size' => 15,
+        '#required' => TRUE,
+      );
+      break;
+  }
   $form['pass'] = array('#type' => 'password',
     '#title' => t('Password'),
     '#maxlength' => 60,
@@ -2027,14 +2062,35 @@ function user_login($form, &$form_state) {
   }
 
   // Display login form:
-  $form['name'] = array('#type' => 'textfield',
-    '#title' => t('Username'),
-    '#size' => 60,
-    '#maxlength' => USERNAME_MAX_LENGTH,
-    '#required' => TRUE,
-  );
-
-  $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal')));
+  switch (variable_get('user_login_name_option', USER_LOGIN_USERNAME_ONLY)) {
+    case USER_LOGIN_USERNAME_ONLY:
+      $form['name'] = array('#type' => 'textfield',
+        '#title' => t('Username'),
+        '#maxlength' => USERNAME_MAX_LENGTH,
+        '#size' => 60,
+        '#required' => TRUE,
+        '#description' => t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal'))),
+      );
+      break;
+    case USER_LOGIN_EMAIL_ONLY:
+      $form['name'] = array('#type' => 'textfield',
+        '#title' => t('E-mail address'),
+        '#maxlength' => EMAIL_MAX_LENGTH,
+        '#size' => 60,
+        '#required' => TRUE,
+        '#description' => t('Enter your @s e-mail address.', array('@s' => variable_get('site_name', 'Drupal'))),
+      );
+      break;
+    case USER_LOGIN_USERNAME_OR_EMAIL:
+      $form['name'] = array('#type' => 'textfield',
+        '#title' => t('Username or e-mail address'),
+        '#maxlength' => EMAIL_MAX_LENGTH,
+        '#size' => 60,
+        '#required' => TRUE,
+        '#description' => t('Enter your @s username or e-mail address.', array('@s' => variable_get('site_name', 'Drupal'))),
+      );
+      break;
+  }
   $form['pass'] = array('#type' => 'password',
     '#title' => t('Password'),
     '#description' => t('Enter the password that accompanies your username.'),
@@ -2070,9 +2126,35 @@ function user_login_default_validators() {
 }
 
 /**
- * A FAPI validate handler. Sets an error if supplied username has been blocked.
+ * A FAPI validate handler. Depending on user_login_name_option, delegates
+ *   validation to user_login_username_validate() and valid_email_address().
  */
 function user_login_name_validate($form, &$form_state) {
+  if (isset($form_state['values']['name'])) {
+    switch (variable_get('user_login_name_option', USER_LOGIN_USERNAME_ONLY)) {
+      case USER_LOGIN_USERNAME_ONLY:
+        user_login_username_validate($form, $form_state);
+        break;
+      case USER_LOGIN_EMAIL_ONLY:
+      if (!valid_email_address($form_state['values']['name'])) {
+          form_set_error('name', t('The e-mail address %email is not valid.', array('%email' => $form_state['values']['name'])));
+        }
+        break;
+      case USER_LOGIN_USERNAME_OR_EMAIL:
+        if (!valid_email_address($form_state['values']['name'])) {
+          // If name is not a valid e-mail address, assume that name is a
+          // username.
+          user_login_username_validate($form, $form_state);
+        }
+        break;
+    }
+  }
+}
+
+/**
+ * A FAPI validate handler. Sets an error if supplied username has been blocked.
+ */
+function user_login_username_validate($form, &$form_state) {
   if (isset($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
     // Blocked in user administration.
     form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
@@ -2096,7 +2178,23 @@ function user_login_authenticate_validate($form, &$form_state) {
       $form_state['flood_control_triggered'] = 'ip';
       return;
     }
-    $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
+    $account = FALSE;
+    switch (variable_get('user_login_name_option', USER_LOGIN_USERNAME_ONLY)) {
+      case USER_LOGIN_USERNAME_ONLY:
+        $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
+        break;
+      case USER_LOGIN_EMAIL_ONLY:
+        $account = db_query("SELECT * FROM {users} WHERE mail = :mail AND status = 1", array(':mail' => $form_state['values']['name']))->fetchObject();
+        break;
+      case USER_LOGIN_USERNAME_OR_EMAIL:
+      if (valid_email_address($form_state['values']['name'])) {
+        $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
+        }
+        if (!$account) {
+        $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
+        }
+        break;
+    }
     if ($account) {
       if (variable_get('user_failed_login_identifier_uid_only', FALSE)) {
         // Register flood events based on the uid only, so they apply for any
@@ -2150,7 +2248,17 @@ function user_login_final_validate($form, &$form_state) {
       }
     }
     else {
-      form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
+      switch (variable_get('user_login_name_option', USER_LOGIN_USERNAME_ONLY)) {
+        case USER_LOGIN_USERNAME_ONLY:
+          form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
+          break;
+        case USER_LOGIN_EMAIL_ONLY:
+          form_set_error('name', t('Sorry, unrecognized e-mail address or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
+          break;
+        case USER_LOGIN_USERNAME_OR_EMAIL:
+          form_set_error('name', t('Sorry, unrecognized username, e-mail address or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
+        break;
+      }
       watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
     }
   }
@@ -2174,7 +2282,21 @@ function user_login_final_validate($form, &$form_state) {
 function user_authenticate($name, $password) {
   $uid = FALSE;
   if (!empty($name) && !empty($password)) {
-    $account = user_load_by_name($name);
+    $account = FALSE;
+    switch (variable_get('user_login_name_option', USER_LOGIN_USERNAME_ONLY)) {
+      case USER_LOGIN_USERNAME_ONLY:
+        $account = user_load_by_name($name);
+        break;
+      case USER_LOGIN_EMAIL_ONLY:
+        $account = user_load_by_mail($name);
+        break;
+      case USER_LOGIN_USERNAME_OR_EMAIL:
+        $account = user_load_by_mail($name);
+        if (!$account) {
+          $account = user_load_by_name($name);
+        }
+        break;
+    }
     if ($account) {
       // Allow alternate password hashing schemes.
       require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
