Problem/Motivation

If a user registers an account using capital letters in their email address, to be able to reset their password later they need to enter email with exact same capitalization. If they enter email as all lowercase or a different capitalization from original, they aren't able to reset their password.

(I suspect there should be a duplicate issue, but wasn't able to find it).

Proposed resolution

User email should not be case sensitive

Remaining tasks

Contributor tasks needed
Task Novice task? Contributor instructions Complete?
Try to reproduce the issue in Drupal 8 Novice Instructions

User interface changes

API changes

Comments

yesct’s picture

Version: 7.x-dev » 8.0.x-dev
Issue summary: View changes

We should check if the problem can be reproduced in Drupal 8.

mikeburrelljr’s picture

Unable to reproduce in Drupal 8. (Password reset worked as expected when differing case between registered email address and the email address used in the password reset form.)

aburrows’s picture

Status: Active » Needs work
StatusFileSize
new107.31 KB

Yes this is still an issue in 8.x
I tried ALEX@alexburrows.net and the account was created correctly, but upon doing a forgot password with lowercase I got the attached screenshot.
So it sounds like we need to modify when a user is created functionality and any lookups needed to determine the correct data.

stefan.r’s picture

I tried to reproduce this on 8.x HEAD with MySQL and couldn't, @aburrows what are the exact steps to reproduce this?

subhojit777’s picture

I tried the steps as mentioned in this issue's description, but not able to reproduce the problem.

vaibhavjain’s picture

Status: Needs work » Closed (works as designed)

This has been tested on 8.0.x branch, and it works well.
Closing the issue.

tvn’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Closed (works as designed) » Needs work

Moving back to 7.x since it can't be reproduced in Drupal 8.

neerajsingh’s picture

Hi tvn,

I am not able to reproduce this issue on Drupal 7 too. I had followed the following steps:

1. At '/user/register' registered a new user with mail id as 'CAPITAL@mail.com'.
2. Logged in to the website using administrator user and updated the account for 'CAPITAL@mail.com' from BLOCKED to ACTIVE.
3. Logged out from administrator user.
4. Under request password tab 'user/password'. I have tried with different combination of cases(Capital and non capital alphabets at 'CAPITAL@mail.com').

This worked fine for me. Please guide me if I missed any steps in between....

Regards,
Neeraj Singh

cilefen’s picture

Status: Needs work » Closed (cannot reproduce)

I cannot reproduce this on 7.x.

David_Rothstein’s picture

Version: 7.x-dev » 8.0.x-dev
Status: Closed (cannot reproduce) » Postponed (maintainer needs more info)
Issue tags: +Needs backport to D7
Related issues: +#2324701: User login name is case sensitive when using postgreSQL

Given the nature of the issue I assume this could be a problem that only shows up on PostgreSQL databases - @aburrows, can you confirm that's what you were using?

In fact this might be a duplicate of #2324701: User login name is case sensitive when using postgreSQL, and if so that issue may need to be moved to Drupal 8.

aburrows’s picture

I was using MySQL on a vagrant setup but that was a while back, i'll have to check the latest 8.x HEAD to see if it works

klidifia’s picture

This is for PostgreSQL and believe that the issue defined in 2324701 is caused by the same thing. The latest patch there doesn't fix this for the password reset form being case sensitive. Would it would make sense to have that merged into one?

I can confirm that this is indeed an issue in Drupal 8.0.1 with PostgreSQL.

drikc’s picture

Status: Postponed (maintainer needs more info) » Needs review
StatusFileSize
new2.68 KB
new2 KB

The attached patch set the 'case_sensitive' attribute with false for the email field item. It include a test for "reset the password by email" with case sensitive mismatch.

If this case_sensitive attribute, new since D8, is database backend agnostic then the test-only patch should fail (for mysql and postgresql).

Thus this issue isn't related to #2324701: User login name is case sensitive when using postgreSQL. I mean fix isn't related.

drikc’s picture

This fix pgsql translateCondition() (which is triggered now since the email field item now use case_sensitive = FALSE).

drikc’s picture

Small change over #14: fix translateCondition() completely.

spuky’s picture

Issue tags: +Needs security review

Are you sure this is moving in the right direction since as of RFC 5321 section 2.3.11. https://tools.ietf.org/html/rfc5321#section-2.3.11 the local-part of an email address can be case sensitve and it is up to the Domain to decide on this. So capital@domain.com could be a different user than CAPITAL@domain.com. (not very common but possible)

This Issue is a Trade of between minimizing support Issues and Security. To be More Secure Drupal should always treat the localpart case sensitive since there is no means of knowing how the user Domains handles that.

So If going the route of assuming that most of the domains handle their local-part case insensitive which should be fine for most Sites, there should be a config to switch this to the more secure side. And handle the local-part case-sensitve so sites with critical data have a means of changeing that.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

drikc’s picture

I would say that enabling mail's local-part with case sensitive could be quiet cumbersome; users would probably want to reserve each possible combination of capitalisation for the local-part. That's probably the reason why case sensitive isn't much enabled in practice...

That said, having this local-part case sensitive as an option is probably the best solution but I would say this would need to go in a separate issue. Then, this issue is to homogenize the behavior btw database back-ends and I think having case insensitive as a default seems quiet logical...

drikc’s picture

This patch add case insensitive for SQLite beside PostgreSQL (and MySQL as initially).

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

geodaniel’s picture

This patch works for me with PostgreSQL, tried with Drupal 8.2.x. I haven't tested the SQLite equivalent.

Previously I could log in with 'user@example.com' but not 'USER@example.COM', and after the patch I can use either variation.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mxr576’s picture

Can we get this fixed in Drupal 8.6.x at least?

borisson_’s picture

Status: Needs review » Needs work

@mxr576, we need to make sure that this is tested correctly and set to rtbc before we can commit this, and thus fix it in the next drupal release.

I'm pretty sure this will also need a change record.

I found a couple of things that need changing.

  1. +++ b/core/lib/Drupal/Core/Entity/Query/Sql/sqlite/Condition.php
    @@ -0,0 +1,36 @@
    +/**
    + *  * Implements entity query conditions for SQLite databases.
    + *   */
    

    The comment looks wrong.

  2. +++ b/core/lib/Drupal/Core/Entity/Query/Sql/sqlite/Condition.php
    @@ -0,0 +1,36 @@
    +class Condition extends BaseCondition {
    +  /**
    

    Needs a newline

  3. +++ b/core/modules/simpletest/src/TestBase.php
    @@ -1634,4 +1634,24 @@ protected function getConfigSchemaExclusions() {
    +  function strCaseInverse($s) {
    

    I don't think this method should go in this base class. We shouldn't introduce new methods on base classes if they only have one usage, or at least that's how I understand it.

  4. +++ b/core/modules/user/src/Tests/UserPasswordResetTest.php
    @@ -179,6 +179,19 @@ function testUserPasswordReset() {
    +  function testUserPasswordResetCaseInsensitive() {
    

    This should probably go in a functional test instead of a simpletest.

    I don't think it's a good way to test this either.

    We can be more explicit in testing this by using an email address that explicitly has the correct casing?

scott.whittaker’s picture

Is this being back-ported to Drupal 7 at all? Never mind, I see the tag. Curious if anyone has attempted it though?

drikc’s picture

scott.whittaker’s picture

Thanks!

kalpaitch’s picture

Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new7.4 KB
new3.68 KB

A quick re-roll. Have moved login tests to functional tests, but didn't fancy doing the same for password reset tests at the moment as they haven't all been ported yet anyway.

kalpaitch’s picture

StatusFileSize
new7.01 KB
new4.29 KB

Arggh.

The last submitted patch, 30: case_insensitive_login-2490294-30.patch, failed testing. View results

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

jonathanshaw’s picture

Here's a proposed refocusing of this issue:

1. Storage must preserve case
From RFC 2821:

The local-part of a mailbox MUST BE treated as case sensitive. [...] Mailbox domains are not case sensitive. In particular, for some hosts the user "smith" is different from the user "Smith".

Therefore as agreed in #280310: Force {users}.mail to lowercase we MUST NOT force emails to lower case because (albeit in very rare circumstances) mail will not get delivered correctly if the capitalisation is wrong.

2. Assuming that email querying is case insensitive is a security liability
If your email provider is case sensitive and allows two different users to have the addresses smith@example.com and Smith@example.com, then in some circumstances your Drupal account can be compromised by someone deliberately obtaining an address equal to yours but different in capitalisation.

To prevent this:
(a) password reset emails must be sent to the stored email address not the user entered email
(b) email uniqueness validation on the user entity should be case insensitive
(c) external identification integrations like LDAP should take extra steps to verify the exact case matching of a Drupal email and the external email if there is any chance of untrusted case-only-differentiated emails in their system.

3. Making querying by email case sensitive can lead to unexpected behavior
Users frequently enter the case of emails wrongly, and developers frequently forget that users may have miscapitalised their input. e.g. #2876155: Functions to load user by name or email should be case insensitive Therefore Drupal's OOTB UX and DX would be enhanced if email fields were case insensitive by default.

4. In scope here
To do this we need to:
(a) ->setSetting('case_sensitive', FALSE); on EmailItem per#19
(b) test that password reset form sends email to stored email not form-inputted email
(c) test that email uniqueness validation on the user entity does not allow emails that differ only in case
(d) test that using UserStorage::loadByProperties(['mail'=>...) is case insensitive
(e) test that using a user entity query with a mail condition is case insensitive.

5. Out of scope here:
(a) Making login by username case insensitive per #30/31. That should be a seperate issue.
(b) adding Sqllite support for entity query case sensitivity. That should be a seperate issue, if necessary this can be postponed on that.

kalpaitch’s picture

StatusFileSize
new1.84 KB

Re-rolling for my benefit. If it turns out there's any interest in getting this into core then I'd be willing to help, but it doesn't seem to be bothering many people apart from me :)

scott.whittaker’s picture

Absolutely, we use Postgres databases mainly for geo mapping features and case-insensitive emails have been a royal pain for us, though most of our users are on a Drupal 7 site, all our new sites are D8.

jonathanshaw’s picture

I'm happy to keep reviewing if people make patches in the direction of #36.

kalpaitch’s picture

Ok, thanks folks, you're golden.

1. Agreed.
2. That would be my assumption also, although it might be good to get a few more eyes on to confirm it. Does this only stand true when the email address is used for authentication/users?
4. I'll look to add tests back in.
5. Sounds good also.

jonathanshaw’s picture

Uggh. There's a problem I didn't consider. What do we do about duplicate but (case-differentiated) emails already in the system. It's a BC nightmare. We might have to turn case-insensitivity off by default on existing installs.

scott.whittaker’s picture

Why not make a view that lists duplicates and a status report that flags them as an error state? Let the site admins decide how to handle it with their users however they see fit?

jonathanshaw’s picture

#42 is going in the right direction.

We should check for duplicates using hook_requirements ($phase === 'update') and return a REQUIREMENTS_ERROR if there are duplicates.

Maybe we could just put the duplicates in the status message as there should be so few, it shouldn't be too problematic even on a site with a huge number of users. In fact, if there were more than 100 duplicates, we don't need to list them because that site is probably going to need to develop a custom solution to fix them anyway.

I'm relieved, this solution is easier than I feared it would be.

vikashsoni’s picture

StatusFileSize
new90.09 KB

@kalpaitch patches not working giving error would be suggest how i can check it sharing screenshot ....

vladimiraus’s picture

Version: 8.9.x-dev » 9.2.x-dev
StatusFileSize
new1.84 KB

Updated to 9.2. Patch updated.

jonathanshaw’s picture

Status: Needs review » Needs work

NW for #43

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.1.10 (June 4, 2021) and Drupal 9.2.10 (November 24, 2021) were the last bugfix releases of those minor version series. Drupal 9 bug reports should be targeted for the 9.3.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mxr576’s picture

Version: 9.3.x-dev » 9.4.x-dev

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

vladimiraus’s picture

Status: Needs work » Needs review
StatusFileSize
new4.76 KB

Updated with suggestion from #43 and some ideas from https://www.drupal.org/project/drupal/issues/2464481#comment-14544486

vladimiraus’s picture

StatusFileSize
new4.72 KB

Ooops! Proper patch.

daffie’s picture

Status: Needs review » Postponed

We are not going to use the LOWER operator on PostgreSQL. The decision has been made to use GIST indexes instead. For that is the pg_trgm extension required for Drupal 10. See: https://www.drupal.org/docs/system-requirements/database-server-requirem....
The biggest problem is with performance problems with the path alias queries. The patch from that issue also add the code to create those indexes. See: #2988018-71: [PP-1] Performance issues with path alias generated queries on PostgreSQL . When that has landed, we can use that solution in other places, like with #2490294: User email should not be case sensitive.

@VladimirAus: Thank you for working on case insensitive queries on PostgreSQL. It is also something that I would like to get fixed. It would be great if you could do a review of #2988018-71: [PP-1] Performance issues with path alias generated queries on PostgreSQL .

au_dave’s picture

The patch in #51 breaks a site when using Exists or notExists conditions.

Fix provided.

au_dave’s picture

StatusFileSize
new3.27 KB

Actually the patch in #53 breaks other stuff. The latest one is based on @VladimirAus 's two patches.

mxr576’s picture

+    // Load all users on update to check duplcate emails in various cases.
+    $users = \Drupal::entityTypeManager()->getStorage('user')->loadMultiple();

The memory impact of a call like this in a simple hook_requirements() implementation can be huge, even drastic on sites with thousands of users. In addition, loading full user objects are completely unnecessary when only their IDs and email addresses are needed. I'd use plain entity (or even database) queries for this.

jonathanshaw’s picture

Let's do a count query first. If there's more than 100, then don't list them as the site will probably want to figure out a custom solution. If there's less than 100, it will be fine to use loadMultiple() anyway.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

andrew.wang’s picture

Re-rolled #45 for Drupal 9.5.

daffie’s picture

Issue tags: +PostgreSQL
mxr576’s picture

@andrew.wang the update hook that was available in #54 is missing from your patch in #58, what is the reason behind that?

Let's do a count query first. If there are more than 100, then...

This can be a good approach, but how about instead of that magic number (100) we would depend on the value of Settings::get('entity_update_batch_size')?

jonathanshaw’s picture

how about instead of that magic number (100) we would depend on the value of Settings::get('entity_update_batch_size')?

That seems excessive for a minor developer convenience related to a one time update.

mxr576’s picture

That seems excessive for a minor developer convenience related to a one time update.

Well, my reasoning behind suggesting that was that we cannot know if 100 entities are too much or too less on a given downstream project (hosting platform). Downstream developers should know and already have this setting value customized accordingly.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

rosk0’s picture

Status: Postponed » Closed (outdated)
Issue tags: -Needs backport to D7

I believe this should be closed now - the use case of having multiple users with the same email in different capitalization was addressed in https://www.drupal.org/sa-core-2024-004 .

I've just tested the behaviour on the Drupal 10.3.10 and PostgreSQL and it looks perfectly in line with various proposals in this issue:
- account registered for testEmail@test.com
- account registration attempted for testemail@test.com - failed with "Address already taken" message
- password reset for attempt for testemail@test.com sent a password to stored in the system testEmail@test.com

rosk0’s picture

Status: Closed (outdated) » Postponed

I've clearly mixed some wires here - user mail field is case sensitive.

Sorry for the noise.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.