Skip to content

Commit

Permalink
Issue backdrop#227: Check usernames that are email addresses more rig…
Browse files Browse the repository at this point in the history
…idly, only allow if matches email.
  • Loading branch information
Jen Lampton committed Jan 1, 2016
1 parent e98bf1f commit 5dd5f07
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 34 deletions.
1 change: 1 addition & 0 deletions core/modules/system/config/system.core.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"user_admin_role": "",
"user_cancel_method": "user_cancel_block",
"user_email_verification": 1,
"user_email_match": 1,
"user_mail_status_activated_notify": 1,
"user_mail_status_blocked_notify": 0,
"user_mail_status_canceled_notify": 0,
Expand Down
10 changes: 5 additions & 5 deletions core/modules/system/system.module
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ define('BACKDROP_OPTIONAL', 1);
*/
define('BACKDROP_REQUIRED', 2);

/**
* Maximum length of e-mail fields.
*/
define('EMAIL_MAX_LENGTH', 254);

/**
* Maximum number of values in a weight select element.
*
* If the number of values is over the maximum, a text field is used instead.
*/
define('BACKDROP_WEIGHT_SELECT_MAX', 100);

/**
* Maximum length of e-mail fields.
*/
define('EMAIL_MAX_LENGTH', 254);

/**
* The maximum depth for token tree recursion.
*/
Expand Down
93 changes: 88 additions & 5 deletions core/modules/user/tests/user.test
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,9 @@ class UserSignatureTestCase extends BackdropWebTestCase {
* Test that a user, having editing their own account, can still log in.
*/
class UserEditedOwnAccountTestCase extends BackdropWebTestCase {
/**
* Tests a user editing their own account.
*/
function testUserEditedOwnAccount() {
// Change account setting 'Who can register accounts?' to Administrators
// only.
Expand All @@ -1686,6 +1689,29 @@ class UserEditedOwnAccountTestCase extends BackdropWebTestCase {
// Set the new name on the user account and attempt to log back in.
$account->name = $edit['name'];
$this->backdropLogin($account);

// Attempt to change username to an email other than my own.
$edit['name'] = $this->randomName() . '@example.com';
$this->backdropPost('user/' . $account->uid . '/edit', $edit, t('Save'));
$this->assertText(t('An email address was provided as a username, but does not match the account email address.', array('%name' => $edit['name'])), 'Error message found when an email username does not match user email.');
$this->assertNoText(t('The changes have been saved.'), 'The user account was not saved.');

// Lookup user by name to make sure we didn't actually change the name.
$changed = user_load_by_name($edit['name']);
$this->assertFalse($changed, 'Username was not changed to email address other than my own.');

// Change username to my email address.
$edit['name'] = $account->mail;
$this->backdropPost('user/' . $account->uid . '/edit', $edit, t('Save'));
$this->assertText(t('The changes have been saved.'), 'The user account was saved.');

// Test that 'verify_email_match' turned off allows emails that don't match.
config_set('system.core', 'user_email_match', FALSE);

// Change username to random, non-matching email address.
$edit['name'] = $this->randomName() . '@example.com';
$this->backdropPost('user/' . $account->uid . '/edit', $edit, t('Save'));
$this->assertText(t('The changes have been saved.'), 'The user account was saved.');
}
}

Expand Down Expand Up @@ -2013,9 +2039,6 @@ class UserEntityCallbacksTestCase extends BackdropWebTestCase {
$uri = entity_uri('user', $this->account);
$this->assertEqual('user/' . $this->account->uid, $uri['path'], t('Correct user URI.'));
}
<<<<<<< HEAD
}
=======
}

class UserRegistrationTestCase extends UserLoginTestCase {
Expand Down Expand Up @@ -2186,7 +2209,6 @@ class UserRegistrationTestCase extends UserLoginTestCase {
$this->assertEqual($new_user->init, $mail, 'Correct init field.');
}


/**
* Test that login credentials work.
*/
Expand Down Expand Up @@ -2297,5 +2319,66 @@ class UserRegistrationTestCase extends UserLoginTestCase {
$this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][2]['value'], $value + 2, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
}
}

/**
* Tests new users username matches their email if username is an email.
*/
function testRegistrationEmailAsUsername() {
// Don't require email verification.
// Allow registration by site visitors without administrator approval.
config('system.core')
->set('user_email_verification', FALSE)
->set('user_register', USER_REGISTER_VISITORS)
->save();

$mail = $this->randomName() . '@example.com';
$different = $this->randomName() . $mail;

// Set up edit array.
$edit = array();
$edit['mail'] = $mail;
$edit['name'] = $different;
$edit['pass[pass1]'] = $edit['pass[pass2]'] = $this->randomName();

// Attempt to create an account using an email that doesn't match the name.
$this->backdropPost('user/register', $edit, t('Create new account'));
$this->assertText(t('An email address was provided as a username, but does not match the account email address.'), 'Email username does not match user email - error message found.');
$this->assertNoText(t('Registration successful. You are now logged in.'), 'The user was not created and logged in.');

// Attempt to create new account using matching email address.
$edit['name'] = $edit['mail'] = $this->randomName() . '@example.com';

$this->backdropPost('user/register', $edit, t('Create new account'));
$this->assertText(t('Registration successful. You are now logged in.'), 'The user was created and logged in with matching email.');

$new_user = user_load_by_name($edit['name']);
$this->assertTrue(($new_user->name === $edit['name']) && ($new_user->mail === $edit['mail']), 'Created user with matching username and email address.');
}

/**
* Tests new users username not matching their email if username is an email.
*/
function testRegistrationEmailAsUsernameDisabled() {
// Test that 'user_email_match' turned off allows emails that don't match.
config('system.core')
->set('user_email_match', FALSE)
->set('user_email_verification', FALSE)
->set('user_register', USER_REGISTER_VISITORS)
->save();

$mail = $this->randomName() . '@example.com';
$different = $this->randomName() . $mail;

$edit = array();
$edit['mail'] = $mail;
$edit['name'] = $different;
$edit['pass[pass1]'] = $edit['pass[pass2]'] = $this->randomName();

// Attempt to create an account using an email that doesn't match the name.
// This should be OK, as 'vuser_email_match' is disabled.
$this->backdropPost('user/register', $edit, t('Create new account'));
$this->assertNoText(t('An email address was provided as a username, but does not match the account email address.'), 'Email username does not match user email - error message found.');
$this->assertText(t('Registration successful. You are now logged in.'), 'The user was not created and logged in.');
}
}
>>>>>>> Issue #277: Allow users to log in with usernames or e-mail addresses.

8 changes: 8 additions & 0 deletions core/modules/user/user.admin.inc
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ function user_admin_settings($form, &$form_state) {
'#default_value' => $config->get('user_email_verification'),
'#description' => t('New users will be required to validate their e-mail address prior to logging into the site, and will be assigned a system-generated password. With this setting disabled, users will be logged in immediately upon registering, and may select their own passwords during registration.')
);
$form['registration_cancellation']['user_email_match'] = array(
'#type' => 'checkbox',
'#title' => t('When an email address is used as username, require a matching email address.'),
'#default_value' => $config->get('user_email_match'),
);
module_load_include('inc', 'user', 'user.pages');
$form['registration_cancellation']['user_cancel_method'] = array(
'#type' => 'item',
Expand Down Expand Up @@ -567,12 +572,15 @@ function user_admin_settings($form, &$form_state) {
*/
function user_admin_settings_submit($form, &$form_state) {
$values = $form_state['values'];

$config = config('system.core');
$config->set('anonymous', $values['anonymous']);
$config->set('user_admin_role', $values['user_admin_role']);
$config->set('user_cancel_method', $values['user_cancel_method']);
$config->set('user_login_method', $form_state['values']['user_login_method']);
$config->set('user_register', $values['user_register']);
$config->set('user_email_verification', $values['user_email_verification']);
$config->set('user_email_match', $form_state['values']['user_email_match']);
$config->set('user_signatures', $values['user_signatures']);
$config->set('user_pictures', $values['user_pictures']);
$config->set('user_picture_path', $values['user_picture_path']);
Expand Down
8 changes: 8 additions & 0 deletions core/modules/user/user.entity.inc
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,14 @@ class UserStorageController extends EntityDatabaseStorageController {
}
}

if (valid_email_address($entity->name)) {
// Check to see if matching is required.
$user_email_match = config_get('system.core', 'user_email_match');
if ($user_email_match && ($entity->name != $entity->mail)) {
throw new EntityMalformedException('The username and email are both addresses that do not match.');
}
}

if (!empty($entity->picture_upload)) {
$entity->picture = $entity->picture_upload;
}
Expand Down
24 changes: 12 additions & 12 deletions core/modules/user/user.install
Original file line number Diff line number Diff line change
Expand Up @@ -480,17 +480,10 @@ function user_update_1008() {
}
}

/*
* Set default option for login method to use accounts only.
*/
function user_update_1009() {
config_set('user.settings', 'user_login_method', USER_LOGIN_USERNAME_ONLY);
}

/**
* Create the default view for user administration.
*/
function user_update_1010() {
function user_update_1009() {
$view_config = array(
'name' => 'user_admin',
'description' => 'Manage user accounts, roles, and permissions.',
Expand Down Expand Up @@ -1106,10 +1099,6 @@ function user_update_1010() {
}
}

/**
* @} End of "addtogroup updates-7.x-to-1.x"
*/

/**
* Update 'People' menus to 'User accounts'
*/
Expand All @@ -1123,3 +1112,14 @@ function user_update_1010() {
}
$config->save();
}

/*
* Set default option for login method to use accounts only.
*/
function user_update_1011() {
config_set('user.settings', 'user_login_method', USER_LOGIN_USERNAME_ONLY);
}

/**
* @} End of "addtogroup updates-7.x-to-1.x"
*/
30 changes: 19 additions & 11 deletions core/modules/user/user.module
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ define('USERNAME_MAX_LENGTH', 60);
/**
* Maximum length of user email text field.
*/
const EMAIL_MAX_LENGTH = 254;
define('USERMAIL_MAX_LENGTH', 254);

/**
* Users can login with username only.
*/
const USER_LOGIN_USERNAME_ONLY = 'username_only';
define('USER_LOGIN_USERNAME_ONLY', 'username_only');

/**
* Users can login with email address only.
*/
const USER_LOGIN_EMAIL_ONLY = 'email_only';
define('USER_LOGIN_EMAIL_ONLY', 'email_only');

/**
* Users can login using either username or email address.
*/
const USER_LOGIN_USERNAME_OR_EMAIL = 'username_or_email';
define('USER_LOGIN_USERNAME_OR_EMAIL', 'username_or_email');

/**
* Only administrators can create user accounts.
Expand Down Expand Up @@ -869,9 +869,12 @@ function user_validate_current_pass(&$form, &$form_state) {
*/
function user_account_form_validate($form, &$form_state) {
$account = $form['#user'];
$mail = $form_state['values']['mail'];

// Validate new or changing username.
if (isset($form_state['values']['name'])) {
if ($error = user_validate_name($form_state['values']['name'])) {
$name = $form_state['values']['name'];
if ($error = user_validate_name($name)) {
form_set_error('name', $error);
}
// Cast the user ID as an integer. It might have been set to NULL, which
Expand All @@ -880,19 +883,24 @@ function user_account_form_validate($form, &$form_state) {
$name_taken = (bool) db_select('users')
->fields('users', array('uid'))
->condition('uid', (int) $account->uid, '<>')
->condition('name', db_like($form_state['values']['name']), 'LIKE')
->condition('name', db_like($name), 'LIKE')
->range(0, 1)
->execute()
->fetchField();

if ($name_taken) {
form_set_error('name', t('The name %name is already taken.', array('%name' => $form_state['values']['name'])));
form_set_error('name', t('The name %name is already taken.', array('%name' => $name)));
}
// Check whether the user name provided is an email address. If so, make
// sure it matches the mail value.
if (config('system.core')->get('user_email_match') && (valid_email_address($name))) {
if ($name !== $mail) {
form_set_error('name', t('An email address was provided as a username, but does not match the account email address.'));
}
}
}
}

$mail = $form_state['values']['mail'];

if (!empty($mail)) {
$mail_taken = (bool) db_select('users')
->fields('users', array('uid'))
Expand Down Expand Up @@ -938,7 +946,7 @@ function user_login_block($form) {
$form['name'] = array(
'#type' => 'textfield',
'#title' => $credentials == USER_LOGIN_USERNAME_ONLY ? t('Username') : ($credentials == USER_LOGIN_EMAIL_ONLY ? t('E-mail address') : t('Username or e-mail')),
'#maxlength' => $credentials == USER_LOGIN_USERNAME_ONLY ? USERNAME_MAX_LENGTH : EMAIL_MAX_LENGTH,
'#maxlength' => $credentials == USER_LOGIN_USERNAME_ONLY ? USERNAME_MAX_LENGTH : USERMAIL_MAX_LENGTH,
'#size' => 15,
'#required' => TRUE,
'#weight' => 1,
Expand Down Expand Up @@ -1498,7 +1506,7 @@ function user_login($form, &$form_state) {
$credentials = config_get('user.settings', 'user_login_method');
$form['name'] = array('#type' => 'textfield',
'#title' => $credentials == USER_LOGIN_USERNAME_ONLY ? t('Username') : ($credentials == USER_LOGIN_EMAIL_ONLY ? t('E-mail address') : t('Username or e-mail')),
'#maxlength' => $credentials == USER_LOGIN_USERNAME_ONLY ? USERNAME_MAX_LENGTH : EMAIL_MAX_LENGTH,
'#maxlength' => $credentials == USER_LOGIN_USERNAME_ONLY ? USERNAME_MAX_LENGTH : USERMAIL_MAX_LENGTH,
'#size' => 60,
'#required' => TRUE,
);
Expand Down
2 changes: 1 addition & 1 deletion core/modules/user/user.pages.inc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function user_pass() {
'#type' => 'textfield',
'#title' => t('Username or e-mail address'),
'#size' => 60,
'#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH),
'#maxlength' => max(USERNAME_MAX_LENGTH, USERMAIL_MAX_LENGTH),
'#required' => TRUE,
'#default_value' => isset($_GET['name']) ? $_GET['name'] : '',
);
Expand Down

0 comments on commit 5dd5f07

Please sign in to comment.