Skip to content
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

Add beforeLogin trigger with support for auth providers #5445

Merged
merged 5 commits into from
Apr 23, 2019
Merged

Add beforeLogin trigger with support for auth providers #5445

merged 5 commits into from
Apr 23, 2019

Conversation

omairvaiyani
Copy link
Contributor

This has been attempted before a couple of times but never seen to completion. I used some of the ideas by @carlosapgomes in his now closed PR, however most of the work was too out of sync with the current state of the library.

Currently:
User sign ups can be validated, rejected and side-effects issued in beforeSave on Parse.User. There is no similar functionality for user logins.

Use cases:

  • Blocking an account from logging in (for example, if they are banned).
  • Recording a login event for analytics.
  • Notifying user by email if a login occurred at an unusual IP address.

Motivation / Bias:
We have a multi-tenanted platform wherein each client has their own subdomain. They share the same database and so, theoretically users from subdomain-a can legally login to subdomain-b. This new trigger allows us to check the request headers against the user to verify if the login is appropriate.

Example usage:

// In cloud code
Parse.Cloud.beforeLogin(async request => { 
  const { object: user }  = request;
  if(user.get('isBanned')) {
   throw new Error('Sorry, you are a naughty boy.')
  }
});

// On the client
await Parse.User.logIn('naughty', 'pass123'); // rejected with "Sorry, you are a naughty boy."

Considerations:
This trigger behaves in a similar manner to other triggers:

  • It sends a TriggerRequest that contains object, headers, ip, installationId, etc
  • Like afterSave on Parse.User, it will not save mutations to the user unless explicitly saved.
  • It will return a Parse.Error if an exception is thrown
  • It waits for any promises to resolve

The trigger has some unique behaviours not seen in other triggers:

  • It does not accept a className or Parse.Object constructor as the first argument; it is only meant for Parse.User
  • It does not set the user on the request object - technically, the user has not yet been provided a session until after beforeLogin is successfully completed

Some specific behaviours with regards to signup/login:

  • It does not run on sign up
  • It does run on username/pass AND authProvider logins
  • It will not run if the login credentials are incorrect

Please let me know if there are side-effects that I have not accounted for in the added unit tests.

@omairvaiyani omairvaiyani mentioned this pull request Mar 23, 2019
@codecov
Copy link

codecov bot commented Mar 23, 2019

Codecov Report

Merging #5445 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #5445      +/-   ##
==========================================
+ Coverage   93.93%   93.94%   +<.01%     
==========================================
  Files         123      123              
  Lines        9024     9035      +11     
==========================================
+ Hits         8477     8488      +11     
  Misses        547      547
Impacted Files Coverage Δ
src/triggers.js 94.49% <ø> (ø) ⬆️
src/Routers/UsersRouter.js 93.5% <100%> (+0.04%) ⬆️
src/cloud-code/Parse.Cloud.js 97.43% <100%> (+0.21%) ⬆️
src/RestWrite.js 93.52% <100%> (+0.08%) ⬆️

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 d64a23b...f7ab0a9. Read the comment docs.

@acinader
Copy link
Contributor

@stage88 or @georgesjamous would either of you be willing to look at this pull request and give feedback on:

  1. would this be an appropriate feature to add
  2. does the code look like it is doing what it is supposed to
  3. is it well covered
  4. what documentation would need to be written or changed?

Copy link
Contributor

@stage88 stage88 left a comment

Choose a reason for hiding this comment

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

Looks good!

Would it be worth guarding against maintainers accidentally adding beforeLogin to classes other then _User?

See function validateClassNameForTriggers in https://github.com/parse-community/parse-server/blob/master/src/triggers.js.

Also see this test: 'should validate triggers correctly'.

@omairvaiyani
Copy link
Contributor Author

Thanks for taking a look @stage88

I've added the assertions as you suggested with one caveat. The test case 'should validate triggers correctly' would (prior to the latest commits) not throw given that the beforeLogin function was automatically setting the className to _User. I've now adjusted the code for better consistency.

@stage88
Copy link
Contributor

stage88 commented Apr 23, 2019

Great effort 👏, thanks @omairvaiyani.

@georgesjamous this looks good to me.

CC @acinader

@@ -41,6 +42,11 @@ function validateClassNameForTriggers(className, type) {
// TODO: Allow proper documented way of using nested increment ops
throw 'Only afterSave is allowed on _PushStatus';
}
if (type === Types.beforeLogin && className !== '_User') {
// TODO: check if upstream code will handle `Error` instance rather
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

@TomWFox
Copy link
Contributor

TomWFox commented Apr 24, 2019

@omairvaiyani I've started a draft PR for the documentation of this features in #617 on the docs repo. It would be great if you could take a look.

@omairvaiyani
Copy link
Contributor Author

@TomWFox that was quick! I've added some suggestions but nothing major.

UnderratedDev pushed a commit to UnderratedDev/parse-server that referenced this pull request Mar 21, 2020
…ity#5445)

* Add beforeLogin trigger with support for auth providers

* adjust comment that boxed off beforeLogin to a negative use-case only

* add internal error to help future maintainers regarding use of beforeLogin

* let beforeLogin accept className or constructor like other hook types

* add assertions for beforeLogin trigger className validation
@EricNetsch
Copy link

@omairvaiyani @TomWFox
This is a cool addition. Is there any way to retrieve the auth provider in the request? Ex. Facebook, password, {custom}.

Trying to only run a verification check when a user logs-in with a specific auth provider.
Thanks.

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.

5 participants