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

@@ -50,6 +50,7 @@ export class Config {
this.preventLoginWithUnverifiedEmail = cacheInfo.preventLoginWithUnverifiedEmail;
this.emailVerifyTokenValidityDuration = cacheInfo.emailVerifyTokenValidityDuration;
this.accountLockout = cacheInfo.accountLockout;
this.passwordPolicy = cacheInfo.passwordPolicy;
this.appName = cacheInfo.appName;
this.analyticsController = cacheInfo.analyticsController;
@@ -79,7 +80,8 @@ export class Config {
expireInactiveSessions,
sessionLength,
emailVerifyTokenValidityDuration,
accountLockout
accountLockout,
passwordPolicy
}) {
const emailAdapter = userController.adapter;
if (verifyUserEmails) {
@@ -88,6 +90,8 @@ export class Config {
this.validateAccountLockoutPolicy(accountLockout);
this.validatePasswordPolicy(passwordPolicy);
if (typeof revokeSessionOnPasswordReset !== 'boolean') {
throw 'revokeSessionOnPasswordReset must be a boolean value';
}
@@ -113,6 +117,35 @@ export class Config {
}
}
static validatePasswordPolicy(passwordPolicy) {
if (passwordPolicy) {
if (passwordPolicy.resetTokenValidityDuration !== undefined && (typeof passwordPolicy.resetTokenValidityDuration !== 'number' || passwordPolicy.resetTokenValidityDuration <= 0)) {
throw 'passwordPolicy.resetTokenValidityDuration must be a positive number';
}
if(passwordPolicy.validatorPattern && !(passwordPolicy.validatorPattern instanceof RegExp)) {
throw 'passwordPolicy.validatorPattern must be a RegExp.';
}
if(passwordPolicy.validatorCallback && typeof passwordPolicy.validatorCallback !== 'function' ) {
throw 'passwordPolicy.validatorCallback must be a function.';
}
if(passwordPolicy.doNotAllowUsername && typeof passwordPolicy.doNotAllowUsername !== 'boolean') {
throw 'passwordPolicy.doNotAllowUsername must be a boolean value.';
}
}
}
// if the passwordPolicy.validatorPattern is configured then setup a callback to process the pattern
static setupPasswordValidator(passwordPolicy) {
if (passwordPolicy && passwordPolicy.validatorPattern) {
passwordPolicy.patternValidator = (value) => {
return passwordPolicy.validatorPattern.test(value);
}
}
}
static validateEmailConfiguration({emailAdapter, appName, publicServerURL, emailVerifyTokenValidityDuration}) {
if (!emailAdapter) {
throw 'An emailAdapter is required for e-mail verification and password resets.';
@@ -163,6 +196,14 @@ export class Config {
return new Date(now.getTime() + (this.emailVerifyTokenValidityDuration*1000));
}
generatePasswordResetTokenExpiresAt() {
if (!this.passwordPolicy || !this.passwordPolicy.resetTokenValidityDuration) {
return undefined;
}
const now = new Date();
return new Date(now.getTime() + (this.passwordPolicy.resetTokenValidityDuration * 1000));
}
generateSessionExpiresAt() {
if (!this.expireInactiveSessions) {
return undefined;