-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Adding support for optional Password Policy #3032
Adding support for optional Password Policy #3032
Conversation
validator support in passwordPolicy that can be used to enforce strong passwords.
// if the passwordPolicy.validator is configured as a string or regex then convert it to a function to process the pattern | ||
static setupPasswordValidator(passwordPolicy) { | ||
if (passwordPolicy && passwordPolicy.validator) { | ||
if (typeof passwordPolicy.validator === 'string') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we support a function here too? this could be useful if the user is not RegExp fluent :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@flovilmart
Yes, it already does. I added the support after seeing your comment in a related issue :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest instead of having validator
that can be a string, function, or regex, you have a regex
option and a function
option. Overloading interfaces by using typeof
tends to get confusing IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point Drew !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@drew-gross please correct me if my understanding is wrong.
There will be two mutually exclusive options - validatorPattern
(RegExp) and validatorCallback
(function)
One of them should be overriding if both options are specified. I think the callback function option should take priority.
Please confirm then I will go ahead and make changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say both should be required if both are provided. So if you a provide a callback and a pattern, then the password must pass both to be considered valid. Either that or throw if both are provided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got your point Drew. I think it's a better idea to require both to pass if both are provided.
@flovilmart @cherukumilli what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bhaskaryasa
I agree with @drew-gross. If both are provided then we should check both. If only one of them is provided then just check only that one.
@flovilmart |
…pdatePassword thus avoid duplicate check for password validator in updateUserPassword.
…e-server into password-policy
@bhaskaryasa updated the pull request - view changes |
@bhaskaryasa updated the pull request - view changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small thing with the fdescribe, otherwise it's 💯!
const request = require('request'); | ||
const Config = require('../src/Config'); | ||
|
||
fdescribe("Password Policy: ", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry!! corrected that.
@bhaskaryasa updated the pull request - view changes |
@cherukumilli you had concerns about the naming of a column, I don't want to go over as you already contributed a lot to that section of the platform. Let me know if there's any concern, otherwise I'll merge. |
user.set('email', '[email protected]'); | ||
return user.signUp(); | ||
}) | ||
.then(user => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bhaskaryasa
one more small nit...
Can you please combine lines 31 and 32?
.then(user => { | ||
Parse.User.requestPasswordReset("[email protected]"); | ||
}) | ||
.then(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bhaskaryasa
one more...
Can you please combine lines 34 and 35?
@@ -0,0 +1,697 @@ | |||
"use strict"; | |||
|
|||
const request = require('request'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bhaskaryasa
Can you please userequest-promise
or request-promise-native
instead of just request
?
setTimeout(() => { | ||
expect(sendEmailOptions).not.toBeUndefined(); | ||
|
||
request.get(sendEmailOptions.link, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bhaskaryasa
request-promise provides a nice promise way of calling get.
Can u pls look into using it?
}, | ||
publicServerURL: "http://localhost:8378/1" | ||
}) | ||
.then(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bhaskaryasa
can u pls merge the above two lines?
user.set('email', '[email protected]'); | ||
return user.signUp(); | ||
}) | ||
.then(user => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can u pls merge the above two lines?
.then(user => { | ||
Parse.User.requestPasswordReset("[email protected]"); | ||
}) | ||
.then(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can u pls merge the above two llines?
setTimeout(() => { | ||
expect(sendEmailOptions).not.toBeUndefined(); | ||
|
||
request.get(sendEmailOptions.link, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can u pls use request-promise
or request-promise-native
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure. will change to request-promise as the dependency already exists.
}, | ||
publicServerURL: "http://localhost:8378/1" | ||
}) | ||
.then(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can u please merge the two above lines?
fail('passwordPolicy.resetTokenValidityDuration "not a number" test failed'); | ||
done(); | ||
}) | ||
.catch(err => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pls merge the above two lines
}, | ||
publicServerURL: "http://localhost:8378/1" | ||
}) | ||
.then(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can u pls merge the above two lines and apply the same change to other occurrences of it?
user.set('email', '[email protected]'); | ||
user.signUp().then(() => { | ||
done(); | ||
}, (error) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we use .catch(error => {
here? and also other occurrences of this pattern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I think I used this pattern at few other places as well. Will change them.
@flovilmart IMO, we should change the name of @bhaskaryasa 's concern was that we might invalidate some of the password reset links when a developer upgrades to this new version of the column name i.e., from I think the risk is pretty low, as the user can always request to have their password reset again. The new password reset token will be created in the WDYT? |
…pdatePassword thus avoid duplicate check for password validator in updateUserPassword.
@bhaskaryasa updated the pull request - view changes |
Rebased and fixed the issue. It should be good now. |
@@ -7,6 +7,7 @@ node_js: | |||
services: | |||
- postgresql | |||
- redis-server | |||
- docker |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bhaskaryasa
The above changes don't appear to be yours but somehow showed up in your push.
Looks like you are pulling in changes from some other branch
or
you might have missed a rebase step
I see there are some other similar changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes the rebase step seems to be off...
@bhaskaryasa updated the pull request - view changes |
I've tapped the update button, seems to be good, waiting for travis to finish and merging |
There seems to be an issue with postgres with invalid links. We can't merge it as is, otherwise we'll loose our ability to generate latest branches upon merges. Can you have a look? I'm pretty sure this is trivial. https://travis-ci.org/ParsePlatform/parse-server/jobs/175176642#L1719 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Failing with Postgres, can you please have a look? Seems that the invalid link expiration is not working correctly.
you can also use it_exclude_dbs(['postgres'])
to mark the test as not run for postgres
@bhaskaryasa updated the pull request - view changes |
@flovilmart Fixed the issue with postgres. I see that all tests are through now. |
Fixes: #2734 |
@flovilmart - I am working on additional settings to password-policy. Do you think this PR can be merged so that I can base my new work on top of it? |
@cherukumilli , please merge when you think it's good! |
@flovilmart |
* adds resetTokenValidityDuration setting * adds a validator to validate password that can be used to enforce strong passwords * adds unit tests for passwordPolicy.validator * adds unit tests to to fail reset password function if password is not in a valid format * updates README.md for passwordPolicy * prevents duplicate check for password validator in updateUserPassword * adds optional setting to disallow username in password * updates test cases to use fdescribe instead of describe * updates test cases to use request-promise instead of request * adds ability to use a RegExp or Callback function or both for a passwordPolicy.validator * expect username parameter in redirect to password_reset_success * adds support for _perishable_token_expires_at in postgres
* adds resetTokenValidityDuration setting * adds a validator to validate password that can be used to enforce strong passwords * adds unit tests for passwordPolicy.validator * adds unit tests to to fail reset password function if password is not in a valid format * updates README.md for passwordPolicy * prevents duplicate check for password validator in updateUserPassword * adds optional setting to disallow username in password * updates test cases to use fdescribe instead of describe * updates test cases to use request-promise instead of request * adds ability to use a RegExp or Callback function or both for a passwordPolicy.validator * expect username parameter in redirect to password_reset_success * adds support for _perishable_token_expires_at in postgres
Introducing two settings under passwordPolicy.
validators
Two settings can be used to enforce strong passwords as required by the application. They will be applied at both sign up and password reset. The settings are optional and either one or both can be specified. If both are specified then both the validations must match to accept the password.
Issue #2734
Optional setting to specify a regular expression that the password must match
Optional setting to specify a callback function that returns the validation result as true/false.
doNotAllowUsername
By enabling this setting, the parse server will not allow password to have username in it during signup or password reset
resetTokenValidityDuration
Currently the link that is sent to the user as result of the call to requestPasswordReset never expires. This setting allows the application to define the validity duration of these links. When this is enabled with a valid value, parse server will show invalid_link page if the link has expired.
more settings...
More work needed for additional settings under passwordPolicy. Some of them are: