Skip to content

Case insensitive signup #5634

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 40 commits into from
Feb 14, 2020

Conversation

acinader
Copy link
Contributor

@acinader acinader commented Jun 4, 2019

todo:

  • check if any consideration for linked account needs to be addressed
  • ensure proper indexes for email and username at server start
  • configurability
  • document

fixes: #3990

@codecov
Copy link

codecov bot commented Jun 5, 2019

Codecov Report

Merging #5634 into master will increase coverage by 67.27%.
The diff coverage is 100%.

Impacted file tree graph

@@             Coverage Diff             @@
##           master    #5634       +/-   ##
===========================================
+ Coverage   16.25%   83.53%   +67.27%     
===========================================
  Files         166      169        +3     
  Lines       11632    11734      +102     
===========================================
+ Hits         1891     9802     +7911     
+ Misses       9741     1932     -7809
Impacted Files Coverage Δ
src/Adapters/Storage/Mongo/MongoCollection.js 97.61% <100%> (+92.85%) ⬆️
src/Adapters/Files/GridStoreAdapter.js 46.37% <0%> (ø)
src/cli/definitions/parse-live-query-server.js 100% <0%> (ø)
src/LiveQuery/SessionTokenCache.js 86.95% <0%> (ø)
src/Controllers/index.js 96.66% <0%> (+1.11%) ⬆️
src/logger.js 100% <0%> (+9.09%) ⬆️
src/index.js 100% <0%> (+9.52%) ⬆️
src/Controllers/AdaptableController.js 96% <0%> (+16%) ⬆️
src/Adapters/Logger/WinstonLogger.js 100% <0%> (+19.14%) ⬆️
src/Adapters/MessageQueue/EventEmitterMQ.js 95% <0%> (+20%) ⬆️
... and 139 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d5deca8...8227dca. Read the comment docs.

@acinader
Copy link
Contributor Author

acinader commented Jun 5, 2019

Now with a quick first pass.

  1. I'll take a look at the query plan difference and post my findings here
  2. I assume that logging in with facebook, twitter, etc likely has the same issue as anonymous. How to solve for that.
  3. I have not yet, in any way contemplated the implications of including _auth_data_anonymous in specialQuerykeys

@acinader
Copy link
Contributor Author

acinader commented Jun 5, 2019

@dplewis

  1. Any idea why postgress tests are failing? Probably this? https://github.com/parse-community/parse-server/pull/5634/files#diff-3646535e0655c134862bb00401c8097cR624

  2. Any ideas on how I could systematically skip linked accounts in the username validation? The index on the username will still prevent any duplicates, so it's safe to ignore for this check.

FYI, to anyone following this, it is my goal to allow mixed case username's, but not to allow two usernames that would be equivalent in a case insensitive comparison.

@dplewis
Copy link
Member

dplewis commented Jun 5, 2019

@acinader I should have sometime this week to look.

@acinader
Copy link
Contributor Author

i should probably take care of email too....

acinader added 3 commits June 21, 2019 08:01
1. also make email validation case insensitive
2. update comments to reflect what this change does
@acinader acinader requested review from dplewis and davimacedo June 21, 2019 16:33
@acinader
Copy link
Contributor Author

@dplewis @davimacedo Hi Guys. I'd like to get this resolved.

@davimacedo any interest in reviewing this? Any questions?

@dplewis I could use your help on two things:

  1. I think we can build the exclusions for registered auth adapters dynamically for the RestWrite username query. You've been in the auth adapter stuff, so I thought I'd bounce off you before I try and figure it out...

  2. Can you look at the prostgres failed test? I don't run postgres and would really like to avoid it (i'd be more inclined to drop postgres support if maintaining it falls on me :)...especially cause there are already two languishing pr's for postgres (maybe there's someone we should be adding as a mainter on that front???))

@acinader
Copy link
Contributor Author

acinader commented Jun 21, 2019

@aprato i think i've addressed your concerns too.

@davimacedo
Copy link
Member

@acinader The PR looks good to me for what it aims to do, but I have two questions:

  1. I can't sign up davimacedo and DAVIMACEDO, but if I sign up DAVIMACEDO, I can't sign in davimacedo. It would be perhaps another issue but I think that sign in and sign up should follow the same rule.
  2. I'm little bit afraid of the regex search that can degenerate the performance on a big users table. I was looking at Username/email uniqueness is case-sensitive #3990: don't you think that lowercasing everything when reading/writing would be better (it would also solve question 1)?

@davimacedo
Copy link
Member

I've just found out why Postgres is failing. You are searching for _auth_data_anonymous and it does not exist in the User class (it works well for Mongo but does not work for Postgres). You just need to add the following line of code right after the line https://github.com/parse-community/parse-server/blob/master/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js#L965:

fields._auth_data_anonymous = { type: 'String' }; // Is it a String? I am not sure

@acinader
Copy link
Contributor Author

  • On your point 1: Case insensitive login

I'm starting with the assumption that if a user puts in a username of 'TomWFox', we need to preserve the case and cannot simply lowercase it on save.

I'd also want to check how Google and GitHub handle it. i.e. can @TomWFox login to GitHub with tomwfox? @TomWFox can you check and let us know?

In any event, I view that a separate, but related issue that is not exacerbated by fixing case sensitive sign up.

  • On your point 2: After looking at it more closely, you are right and this solution is not acceptable from a performance standpoint. I will look into a solution using a case insensitive index on username.

  • Another concern I haven't adequately addressed yet is how to exclude Auth Adapter created usernames from being rejected if they fail the case insensitive test when they are actually different when tested with case sensitive.

I'm hoping that I can get some guidance or a pointer to an existing test from @dplewis on how to cover the AuthAdapter cases for anonymous and things like facebook.

Addressing the AuthAdapter is also blocker.

...back to drawing board.

@acinader
Copy link
Contributor Author

@davimacedo do you use postgress, or do you just use for testing with parse?

@TomWFox
Copy link
Contributor

TomWFox commented Jun 23, 2019

@acinader I can login as tomwfox.

@davimacedo
Copy link
Member

@acinader

  • I use Postgres only for testing the PRs.
  • Most of web-sites I see:
    -- allow an account like DaviMacedo (and then show the acocunt like this)
    -- Does not allow a second account like davimacedo (case insensitive sign up)
    -- Allow to sign in as davimacedo (case insensitive sign in)
  • What I think we could do:
    -- Store both the original username and the lowercase version of it
    -- Create two additional options to the Parse Server (enableInsensitiveSignUp and enableInsensitiveSignIn)

@acinader
Copy link
Contributor Author

acinader commented Jun 24, 2019

@davimacedo

  • I agree 100% with your requirements:
    -- allow an account like DaviMacedo (and then show the acocunt like this)
    -- Does not allow a second account like davimacedo (case insensitive sign up)
    -- Allow to sign in as davimacedo (case insensitive sign in)

  • I have an alternate design implementation from your suggestion that you can see the start of with bbc1d73 which I think proves out that it is doable in a performant way. I verified that with the proper index, the index is used and the key inspection is limited to the range of insensitive options.

db.getCollection('_User').createIndex({ username: 1 }, { collation: { strength: 2, locale: 'en_US' }, name: 'username_insensitive', background: true});

  • My current design proposal:

    • At startup ensure a case insensitive index on the two fields
    • at signup verify with a case insensitive query if enableInsensitiveSignUp is true
    • at login find the user with a case insensitive query if enableInsensitiveSignIn is true
    • ensure that we don't interfere with auth providers
  • Argument for case insensitive index vs. lower case field:

    1. We don't have a mechanism to apply migrations so there's no way for us to 'ensure' that existing installs will create the 'usernameLower' field or to lowercase the email addresses.

    2. An international user with a better understanding of collation for non-latin alphabets will be able to easily parameterize the collation variables.

I've only looked into collation in Postgres casually so far ( i did install it and am looking at how to migrate one of our large mongo db's into it so I can get real query statistics.

Unfortunately, it'll be a few days before I can turn back to this issue. Let me know what you think if you have the chance.

@davimacedo
Copy link
Member

@acinader I love the approach you chose. Let me know if you need any help.

@acinader acinader requested a review from dplewis February 11, 2020 00:40
@acinader
Copy link
Contributor Author

@dplewis I think from mongo perspective, this is ready. I'm confused about the postgres.

@TomWFox any thought on what, if any, additional documentation we would want for this beyond the bug and the changelog?

@TomWFox
Copy link
Contributor

TomWFox commented Feb 11, 2020

@acinader from what I can tell this adds behaviour that I think most devs would expect based on other platforms.

I can have a look to see if there are any points in the docs that would need changing based on this new behaviour but I would say the most important thing is making the change clear to existing devs in the changelog.

@acinader acinader dismissed dplewis’s stale review February 11, 2020 18:44

i think i've addressed

@acinader
Copy link
Contributor Author

@dplewis i think this is ready for your review

@dplewis
Copy link
Member

dplewis commented Feb 13, 2020

@acinader Everything looks good. Can you check and see what this does and should it be case insensitive?

return this.config.database

@acinader
Copy link
Contributor Author

Nice catch! I’ll address. Thanks

unique username that do collide when compared
insensitively can still be created.
@acinader
Copy link
Contributor Author

@dplewis I looked at that section of code and I have no idea how one would even get there!

I looked at git history for a bit and it looks to me that the code section you highlighted came about a year before we added unique constraints on username and password.

While it's possible that we should rip out the section, I'd don't want to do that as it really isn't part of this change I am trying to make.

My changes only affect username and email address validation. When checking validation (which isn't done for anonymous users, for example), the check is more strict, prohibiting both exact matches as well as case insensitive matches, but the database itself has to permit all but an exact match to handle the corner case of anonymous users.

In reviewing what you pointed out, I did want to make extra sure that I am not breaking anonymous users in the rare case that there is a case insensitive collision which I added with 201839a.

I don't know what to do about Postgres, but I think the mongo implementation here is solid.

Copy link
Member

@dplewis dplewis left a comment

Choose a reason for hiding this comment

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

I honestly was thinking the same thing. I have no idea why its there or can we reach it. Maybe there is a test that runs against it that can reach it?

The changes look good to me!

@acinader
Copy link
Contributor Author

no test: https://codecov.io/gh/parse-community/parse-server/compare/201839a6a67541bd251adf14730dbc49067f30f7...201839a6a67541bd251adf14730dbc49067f30f7/src/src/RestWrite.js#L1575

that was a good question!

interesting to see the stuff that isn't covered.

I'll merge this in tomorrow. I can either cook up a releasee tomorrow or wait a week as I'll be away from the keyboard next week.

thanks!

@acinader acinader merged commit fd0b535 into parse-community:master Feb 14, 2020
@acinader acinader deleted the case-insensitive-signup branch February 14, 2020 17:44
@oallouch
Copy link
Contributor

Hi guys,

Any link with #4883 ?

:)

@acinader
Copy link
Contributor Author

Hi @oallouch

I didn't implement it in a generic way

but you could look at the code changes i made here if you wanted to do it and i'd be willing to help you with it if i can find the time.

UnderratedDev pushed a commit to UnderratedDev/parse-server that referenced this pull request Mar 21, 2020
* Always delete data after each, even for mongo.

* Add failing simple case test

* run all tests

* 1. when validating username be case insensitive

2. add _auth_data_anonymous to specialQueryKeys...whatever that is!

* More case sensitivity

1. also make email validation case insensitive
2. update comments to reflect what this change does

* wordsmithery and grammar

* first pass at a preformant case insensitive query.  mongo only so far.

* change name of parameter from insensitive to
caseInsensitive

* Postgres support

* properly handle auth data null

* wip

* use 'caseInsensitive' instead of 'insensitive' in all places.

* update commenet to reclect current plan

* skip the mystery test for now

* create case insensitive indecies for
mongo to support case insensitive
checks for email and username

* remove unneeded specialKey

* pull collation out to a function.

* not sure what i planned
to do with this test.
removing.

* remove typo

* remove another unused flag

* maintain order

* maintain order of params

* boil the ocean on param sequence
i like having explain last cause it seems
like something you would
change/remove after getting what you want
from the explain?

* add test to verify creation
and use of caseInsensitive index

* add no op func to prostgress

* get collation object from mongocollection
make flow lint happy by declaring things Object.

* fix typo

* add changelog

* kick travis

* properly reference static method

* add a test to confirm that anonymous users with
unique username that do collide when compared
insensitively can still be created.

* minot doc nits

* add a few tests to make sure our spy is working as expected
wordsmith the changelog

Co-authored-by: Diamond Lewis <findlewis@gmail.com>
@rdhelms
Copy link

rdhelms commented Mar 31, 2020

@acinader I'm having a bit of trouble understanding the end result here - did the new flags enableInsensitiveSignIn and enableInsensitiveSignUp that were discussed end up being implemented? Should we expect that a user with username Bob@mail.com should be able to login using bob@mail.com?

@acinader
Copy link
Contributor Author

Hi @rdhelms

  1. No, I did not implement the flags
  2. This pull request really only did one thing: prevent successful registration of users with a case insensitive collision of username or email. Nothing else.

You should not expect a user with email Bob@mail.com to be able to login as bob@mail.com

That, of course, would be good and a logical next step from this pull request.

@rdhelms
Copy link

rdhelms commented Apr 1, 2020

Thanks for the clarification @acinader 👍🏻

@mtrezza mtrezza mentioned this pull request Jan 28, 2021
3 tasks
@mtrezza mtrezza removed type:bug Impaired feature or lacking behavior that is likely assumed type:docs Only change in the docs or README labels Jul 11, 2021
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.

Username/email uniqueness is case-sensitive
7 participants