LT-98: Passwords shall be required to be changed every 90 days

- route to changePassword page if the password is passwordExpirationDays old
- passwordExpirationDays property under passwordOptions object sets the time interval when password should be changed (90 days by default)
This commit is contained in:
Aysel Afsar 2016-02-15 13:09:58 -05:00
parent 11e300f013
commit d19e402847
4 changed files with 105 additions and 29 deletions

View File

@ -105,6 +105,10 @@ Template.changePassword.events({
} else {
// Save the new password
ActiveEntry.insertHashedPassword(confirmPassword);
// Update password expiration date
ActiveEntry.updatePasswordSetDate();
// Logout
ActiveEntry.signOut();
// Go to signIn page for new entry

View File

@ -28,7 +28,8 @@ if (Meteor.isClient) {
requireRegexValidation: true,
//requireStrongPasswords: false
passwordHistoryCount: 6,
failedAttemptsLimit: 5
failedAttemptsLimit: 5,
passwordExpirationDays: 90
}
});
@ -50,6 +51,18 @@ if (Meteor.isClient) {
ActiveEntry.configure = function (configObject) {
if (Meteor.isClient) {
// Set passwordOptions if they are not defined
if (!configObject.passwordOptions) {
configObject.passwordOptions = {
showPasswordStrengthIndicator: true,
requireRegexValidation: false,
//requireStrongPasswords: false
passwordHistoryCount: 6,
failedAttemptsLimit: 5,
passwordExpirationDays: 90
}
}
Session.set('Photonic.ActiveEntry', configObject);
}
};
@ -110,45 +123,79 @@ ActiveEntry.verifyFullName = function (fullName) {
};
ActiveEntry.signIn = function (emailValue, passwordValue){
ActiveEntry.verifyPassword(passwordValue);
ActiveEntry.verifyEmail(emailValue);
var ActiveEntryConfig = Session.get('Photonic.ActiveEntry');
var failedAttemptsLimit = ActiveEntryConfig && ActiveEntryConfig.passwordOptions && ActiveEntryConfig.passwordOptions.failedAttemptsLimit || 5;
var passwordExpirationDays = ActiveEntryConfig && ActiveEntryConfig.passwordOptions && ActiveEntryConfig.passwordOptions.passwordExpirationDays || 90;
Meteor.call("getFailedAttemptsCount", emailValue, function(error, failedAttemptsCount) {
// Check account is locked
Meteor.call("isAccountLocked", function (error, isAccountLocked) {
if (error) {
console.warn(error.message);
console.warn(error);
} else {
if (failedAttemptsCount != failedAttemptsLimit) {
Meteor.loginWithPassword({email: emailValue}, passwordValue, function (error, result) {
if (error) {
// Login failed
Meteor.call("updateFailedAttempts", [emailValue, failedAttemptsLimit], function(error, failedAttemptCount) {
if (isAccountLocked) {
ActiveEntry.errorMessages.set('signInError', "Your account has been locked.");
return;
}
Meteor.call("getFailedAttemptsCount", emailValue, function(error, failedAttemptsCount) {
if (error) {
console.warn(error.message);
} else {
if (failedAttemptsCount != failedAttemptsLimit) {
Meteor.loginWithPassword({email: emailValue}, passwordValue, function (error, result) {
if (error) {
console.warn(error);
// Login failed
Meteor.call("updateFailedAttempts", [emailValue, failedAttemptsLimit], function(error, failedAttemptCount) {
if (error) {
console.warn(error);
} else {
if (failedAttemptCount == failedAttemptsLimit) {
ActiveEntry.errorMessages.set('signInError', "Too many failed login attempts. Your account has been locked.");
} else {
ActiveEntry.errorMessages.set('signInError', (failedAttemptsLimit - failedAttemptCount) + " attempts remaining.");
}
}
});
} else {
if (failedAttemptCount == failedAttemptsLimit) {
ActiveEntry.errorMessages.set('signInError', "Too many failed login attempts. Your account has been locked.");
console.log('result', result);
// Reset failed attempts
Meteor.call("resetFailedAttempts", emailValue);
} else {
ActiveEntry.errorMessages.set('signInError', (failedAttemptsLimit - failedAttemptCount) + " attempts remaining.");
// Check password expiration
// if password expired, route to changePassword page
Meteor.call("isPasswordExpired", passwordExpirationDays, function(error, isPasswordExpired) {
if (error) {
console.warn(error);
} else {
if (isPasswordExpired) {
ActiveEntry.errorMessages.set('changePasswordError', 'Your password expired. Please change your password.');
Router.go('/changePassword');
} else {
Router.go(ActiveEntryConfig.signIn.destination);
}
}
});
}
}
});
} else {
console.log('result', result);
Meteor.call("resetFailedAttempts", emailValue);
Router.go(ActiveEntryConfig.signIn.destination);
ActiveEntry.errorMessages.set('signInError', "Your account has been locked.");
}
});
} else {
ActiveEntry.errorMessages.set('signInError', "Your account has been locked.");
}
}
});
}
});
};
ActiveEntry.signUp = function (emailValue, passwordValue, confirmPassword, fullName){
@ -185,7 +232,9 @@ ActiveEntry.signUp = function (emailValue, passwordValue, confirmPassword, fullN
} else {
// Add password in previous password field
ActiveEntry.insertHashedPassword(passwordValue);
ActiveEntry.updatePasswordCreatedDate();
// Update password set date
ActiveEntry.updatePasswordSetDate();
var ActiveEntryConfig = Session.get('Photonic.ActiveEntry');
Router.go(ActiveEntryConfig.signUp.destination);
}
@ -213,8 +262,8 @@ ActiveEntry.insertHashedPassword = function(passwordValue) {
Meteor.call("insertHashedPassword", [new String(passwordValue).hashCode(),passwordHistoryCount]);
};
ActiveEntry.updatePasswordCreatedDate = function() {
Meteor.call("updatePasswordCreatedDate");
ActiveEntry.updatePasswordSetDate = function() {
Meteor.call("updatePasswordSetDate");
};
ActiveEntry.signOut = function (){

View File

@ -68,10 +68,10 @@ Meteor.methods({
if (failedAttemptCount == failedAttemptsLimit) {
return failedAttemptCount;
} else {
if (failedAttemptCount == 4) {
if (failedAttemptCount == (failedAttemptsLimit - 1)) {
// Locked user account
Meteor.users.update({"emails.address": emailAddress}, {$set: {"profile.isLocked": true, failedPasswordAttempts: failedAttemptCount + 1}});
} else if (failedAttemptCount < 4) {
} else if (failedAttemptCount < (failedAttemptsLimit - 1)) {
Meteor.users.update({"emails.address": emailAddress}, {$set: {failedPasswordAttempts: failedAttemptCount + 1}});
}
}
@ -83,7 +83,29 @@ Meteor.methods({
Meteor.users.update({"emails.address": emailAddress}, {$set: {failedPasswordAttempts: 0}});
},
updatePasswordCreatedDate: function() {
Meteor.users.update({_id: Meteor.userId()}, {$set: {"services.password.createdAt": new Date()}});
updatePasswordSetDate: function() {
Meteor.users.update({_id: Meteor.userId()}, {$set: {"services.password.setDate": new Date()}});
},
isPasswordExpired: function(passwordExpirationDays) {
var passwordSetDate = Meteor.users.find({_id: Meteor.userId()}).fetch()[0].services.password.setDate;
passwordSetDate.setDate(passwordSetDate.getDate() + passwordExpirationDays);
if (passwordSetDate <= new Date()) {
return true;
}
return false;
},
isAccountLocked: function(emailAddress) {
// Check if the user actually exists, and if not, stop here
var currentUser = Meteor.users.findOne({"emails.address": emailAddress});
if (!currentUser) {
return;
}
return currentUser.profile.isLocked || false;
}
});

View File

@ -1,5 +1,6 @@
#entrySignIn.entryPage,
#entrySignUp.entryPage
#entrySignUp.entryPage,
#changePassword
.wrapper-auth
.title-auth
color: white