Skip to content

Commit

Permalink
Password requirement custom message (#5399)
Browse files Browse the repository at this point in the history
* Added validationError(custom message) for Password requirement fail

* Changed validationError from valodationError in README.md
  • Loading branch information
pateldharad authored and acinader committed Feb 28, 2019
1 parent 1e7cc7b commit 6eaefd9
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 7 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,9 @@ var server = ParseServer({
// If both are specified, both checks must pass to accept the password
// 1. a RegExp object or a regex string representing the pattern to enforce
validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/, // enforce password with at least 8 char with at least 1 lower case, 1 upper case and 1 digit
// 2. a callback function to be invoked to validate the password
// 2. a callback function to be invoked to validate the password
validatorCallback: (password) => { return validatePassword(password) },
validationError: 'Password must contain at least 1 digit.' // optional error message to be sent instead of the default "Password does not meet the Password Policy requirements." message.
doNotAllowUsername: true, // optional setting to disallow username in passwords
maxPasswordAge: 90, // optional setting in days for password expiry. Login fails if user does not reset the password within this period after signup/last reset.
maxPasswordHistory: 5, // optional setting to prevent reuse of previous n passwords. Maximum value that can be specified is 20. Not specifying it or specifying 0 will not enforce history.
Expand Down
8 changes: 6 additions & 2 deletions spec/PasswordPolicy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ describe('Password Policy: ', () => {
.then(response => {
expect(response.status).toEqual(302);
expect(response.text).toEqual(
`Found. Redirecting to http://localhost:8378/1/apps/choose_password?username=user1&token=${token}&id=test&error=Password%20does%20not%20meet%20the%20Password%20Policy%20requirements.&app=passwordPolicy`
`Found. Redirecting to http://localhost:8378/1/apps/choose_password?username=user1&token=${token}&id=test&error=Password%20should%20contain%20at%20least%20one%20digit.&app=passwordPolicy`
);

Parse.User.logIn('user1', 'has 1 digit')
Expand Down Expand Up @@ -700,6 +700,7 @@ describe('Password Policy: ', () => {
emailAdapter: emailAdapter,
passwordPolicy: {
validatorPattern: /[0-9]+/, // password should contain at least one digit
validationError: 'Password should contain at least one digit.',
},
publicServerURL: 'http://localhost:8378/1',
}).then(() => {
Expand Down Expand Up @@ -764,6 +765,9 @@ describe('Password Policy: ', () => {
})
.catch(error => {
expect(error.code).toEqual(142);
expect(error.message).toEqual(
'Password cannot contain your username.'
);
done();
});
});
Expand Down Expand Up @@ -853,7 +857,7 @@ describe('Password Policy: ', () => {
.then(response => {
expect(response.status).toEqual(302);
expect(response.text).toEqual(
`Found. Redirecting to http://localhost:8378/1/apps/choose_password?username=user1&token=${token}&id=test&error=Password%20does%20not%20meet%20the%20Password%20Policy%20requirements.&app=passwordPolicy`
`Found. Redirecting to http://localhost:8378/1/apps/choose_password?username=user1&token=${token}&id=test&error=Password%20cannot%20contain%20your%20username.&app=passwordPolicy`
);

Parse.User.logIn('user1', 'r@nd0m')
Expand Down
20 changes: 16 additions & 4 deletions src/RestWrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,17 @@ RestWrite.prototype._validatePasswordPolicy = function() {

RestWrite.prototype._validatePasswordRequirements = function() {
// check if the password conforms to the defined password policy if configured
const policyError =
'Password does not meet the Password Policy requirements.';
// If we specified a custom error in our configuration use it.
// Example: "Passwords must include a Capital Letter, Lowercase Letter, and a number."
//
// This is especially useful on the generic "password reset" page,
// as it allows the programmer to communicate specific requirements instead of:
// a. making the user guess whats wrong
// b. making a custom password reset page that shows the requirements
const policyError = this.config.passwordPolicy.validationError
? this.config.passwordPolicy.validationError
: 'Password does not meet the Password Policy requirements.';
const containsUsernameError = 'Password cannot contain your username.';

// check whether the password meets the password strength requirements
if (
Expand All @@ -632,7 +641,7 @@ RestWrite.prototype._validatePasswordRequirements = function() {
// username is not passed during password reset
if (this.data.password.indexOf(this.data.username) >= 0)
return Promise.reject(
new Parse.Error(Parse.Error.VALIDATION_ERROR, policyError)
new Parse.Error(Parse.Error.VALIDATION_ERROR, containsUsernameError)
);
} else {
// retrieve the User object using objectId during password reset
Expand All @@ -644,7 +653,10 @@ RestWrite.prototype._validatePasswordRequirements = function() {
}
if (this.data.password.indexOf(results[0].username) >= 0)
return Promise.reject(
new Parse.Error(Parse.Error.VALIDATION_ERROR, policyError)
new Parse.Error(
Parse.Error.VALIDATION_ERROR,
containsUsernameError
)
);
return Promise.resolve();
});
Expand Down

0 comments on commit 6eaefd9

Please sign in to comment.