Adding support for optional Password Policy (#3032)

* 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
This commit is contained in:
Bhaskar Reddy Yasa
2016-11-17 22:07:51 +05:30
committed by Diwakar Cherukumilli
parent 6be9ee5491
commit cf6ce5b9a3
10 changed files with 918 additions and 16 deletions

View File

@@ -77,6 +77,16 @@ export class UserController extends AdaptableController {
if (results.length != 1) {
throw undefined;
}
if (this.config.passwordPolicy && this.config.passwordPolicy.resetTokenValidityDuration) {
let expiresDate = results[0]._perishable_token_expires_at;
if (expiresDate && expiresDate.__type == 'Date') {
expiresDate = new Date(expiresDate.iso);
}
if (expiresDate < new Date())
throw 'The password reset link has expired';
}
return results[0];
});
}
@@ -125,7 +135,13 @@ export class UserController extends AdaptableController {
}
setPasswordResetToken(email) {
return this.config.database.update('_User', { $or: [{email}, {username: email, email: {$exists: false}}] }, { _perishable_token: randomString(25) }, {}, true)
const token = { _perishable_token: randomString(25) };
if (this.config.passwordPolicy && this.config.passwordPolicy.resetTokenValidityDuration) {
token._perishable_token_expires_at = Parse._encode(this.config.generatePasswordResetTokenExpiresAt());
}
return this.config.database.update('_User', { $or: [{email}, {username: email, email: {$exists: false}}] }, token, {}, true)
}
sendPasswordResetEmail(email) {
@@ -159,11 +175,18 @@ export class UserController extends AdaptableController {
updatePassword(username, token, password, config) {
return this.checkResetTokenValidity(username, token)
.then(user => updateUserPassword(user.objectId, password, this.config))
// clear reset password token
.then(() => this.config.database.update('_User', { username }, {
_perishable_token: {__op: 'Delete'}
}));
.then(user => updateUserPassword(user.objectId, password, this.config))
// clear reset password token
.then(() => this.config.database.update('_User', {username}, {
_perishable_token: {__op: 'Delete'},
_perishable_token_expires_at: {__op: 'Delete'}
})).catch((error) => {
if (error.message) { // in case of Parse.Error, fail with the error message only
return Promise.reject(error.message);
} else {
return Promise.reject(error);
}
});
}
defaultVerificationEmail({link, user, appName, }) {
@@ -189,9 +212,9 @@ export class UserController extends AdaptableController {
// Mark this private
function updateUserPassword(userId, password, config) {
return rest.update(config, Auth.master(config), '_User', userId, {
password: password
});
return rest.update(config, Auth.master(config), '_User', userId, {
password: password
});
}
export default UserController;