Skip to content

Fix username/email case issue in login/signup #1317

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 20, 2020

Conversation

shakti97
Copy link
Contributor

@shakti97 shakti97 commented Mar 9, 2020

I have verified that this pull request:

  • has no linting errors (npm run lint)
  • is from a uniquely-named feature branch and has been rebased on top of the latest master. (If I was asked to make more changes, I have made sure to rebase onto master then too)
  • is descriptively named and links to an issue number, i.e. Fixes #123

Fixes #1314

@shakti97
Copy link
Contributor Author

shakti97 commented Mar 9, 2020

@catarak have a look and suggest required changes:)

@andrewn
Copy link
Member

andrewn commented Mar 27, 2020

This code looks good.

One problem that this uncovers is that it's completely possible to create an account with the username "ABC" or email "SOMETHING@EXAMPLE.COM" but then it's impossible to log in with those credentials?

I think before merging we should check if there are any existing users that will suffer from this problem? And perhaps migrate the DB to use lowercase everywhere.

@catarak
Copy link
Member

catarak commented Apr 6, 2020

Thanks for working on this! The case where this would break would be for all of the users that have uppercase letters stored in the database. I think the way to fix this would be:

  1. Add some code to this commit that checks when a user was created, to not apply the toLowercase() to these users. The date can be an environment variable.
  2. Merge this PR.
  3. Write a migration script that updates all of the users username and password to lowercase.
  4. Run this script.
  5. Remove the date check code and submit a PR.

@catarak
Copy link
Member

catarak commented Apr 6, 2020

I managed to figure out an alternative Mongo query that handles both cases... in the process of testing now!

@catarak
Copy link
Member

catarak commented Apr 6, 2020

I now see the error in this logic... trying to figure out another solution!

@catarak
Copy link
Member

catarak commented Apr 6, 2020

Did some more thinking about what the right behavior is here.

  • Email address should be saved as all lowercase in database. We can run a migration script to update this.
  • When logging in with an email, it is normalized to lower case and then queried with the database.
  • Usernames are stored with their case preserved, but should be are case sensitive unique.
  • When logging in with a username, it is case insensitive.

I'm not sure how to implement the username. In order to do case insensitive querying in MongoDB, you have to use a Regex, which you can't use with an index, or create a text index. Or you could store the username both case sensitive and the username in all lowercase.

@catarak
Copy link
Member

catarak commented Apr 6, 2020

This further supports my theory that building an authentication/authorization system is the hardest problem in software development.

@catarak
Copy link
Member

catarak commented Apr 6, 2020

Got a solution going that uses a RegEx search to lay out how this should actually function. It appears the RegEx search is slow there are other options to explore, but this at least lays out all of the places where the case sensitivity of the username/email matters.

@catarak catarak closed this May 26, 2020
@catarak catarak reopened this May 26, 2020
@catarak catarak force-pushed the login-signup-issue branch from edfe09b to 16860d7 Compare July 14, 2020 19:11
@catarak catarak changed the base branch from master to develop July 14, 2020 19:34
- Add case insensitive indexes for User.email and User.username
- Update user queries by username or email so that they are case
  insensitive
@catarak
Copy link
Member

catarak commented Jul 14, 2020

I had a breakthrough and now case-insensitive searches are working! Stuff that's left to do:

  • Write script to migrate all emails to lowercase. (This is technically unnecessary, but it will remove the necessity for case-insensitive searches for email, which is a nice plus)
  • Make a plan for how to handle emails and usernames that are currently duplicated by case. I imagine this is a relatively small number.

@@ -43,7 +43,7 @@ passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, don
* Authentificate using Basic Auth (Username + Api Key)
*/
passport.use(new BasicStrategy((userid, key, done) => {
User.findOne({ username: userid }, (err, user) => { // eslint-disable-line consistent-return
User.findOne({ username: userid }).collation({ locale: 'en', strength: 2 }).exec((err, user) => { // eslint-disable-line consistent-return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add statics on the User model called User.findByUsername() and User.findByEmail() that will perform the User.findOne().collation(...) query.

This avoids duplication and ensures we won't forget to call it. It also means those statics can have a comment about what collation is doing as it's not very obvious.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion! Good idea.

@catarak
Copy link
Member

catarak commented Jul 15, 2020

I did some thinking about how to handle case-sensitive duplicates of email addresses currently in the database, and this is my plan of action:

  1. Make a separate PR that just adds a case-insensitive index to User.emails, and handles all of the case sensitivity issues for just emails. Additionally, make sure users cannot create new usernames that already exist in the database with different case.
  2. Write a script that iterates through all of the accounts with the same email (with different case), merges them to one account (the first one the user created), and then notifies the user via email.
  3. Write a script that migrates all email addresses to be all lowercase.
  4. Remove collation/case-insensitive handling for email addresses.
  5. Handle username case sensitivity issues, and make a plan for dealing with duplicate usernames in the database.

WHEW.

catarak added 5 commits July 15, 2020 17:33
- Add new static methods to user model
  - `findByEmailAndUsername`
  - renames `findByMailOrName` to `findByEmailOrUsername`
  - `findByUsername`
  - `findByEmail`
- Reverts case insensitive behavior for username
- Update the emailConsolidation script so that it will de-duplicate the
  first duplicated user
- Sends email to user alerting them that the consolidation has taken
  place.
@catarak
Copy link
Member

catarak commented Jul 20, 2020

Since I've now run the update script, I'm going to merge this into develop, so it gets into the next release and prevent further duplicate emails. I will figure out the email migration/how to handle duplicate usernames in another PR.

@catarak catarak merged commit 4506c2b into processing:develop Jul 20, 2020
@catarak
Copy link
Member

catarak commented Jul 20, 2020

Just did a query, and it turns out there are 5449 usernames that have duplicates. I unfortunately don't really see a way to allow users to login with their username, case-insensitive, that wouldn't involve changing usernames for users and therefore possibly changing urls. For that reason, I may just leave usernames as case sensitive, but prevent future duplicates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Signup new account using caps in name on https://editor.p5js.org
3 participants