diff --git a/Packages/active-entry/components/changePassword/changePassword.js b/Packages/active-entry/components/changePassword/changePassword.js index c903840ce..bbe87240a 100755 --- a/Packages/active-entry/components/changePassword/changePassword.js +++ b/Packages/active-entry/components/changePassword/changePassword.js @@ -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 diff --git a/Packages/active-entry/lib/ActiveEntry.js b/Packages/active-entry/lib/ActiveEntry.js index 0f68ab57a..211222264 100755 --- a/Packages/active-entry/lib/ActiveEntry.js +++ b/Packages/active-entry/lib/ActiveEntry.js @@ -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 (){ diff --git a/Packages/active-entry/server/methods.js b/Packages/active-entry/server/methods.js index 9dab3cb13..547874e48 100644 --- a/Packages/active-entry/server/methods.js +++ b/Packages/active-entry/server/methods.js @@ -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; } + }); diff --git a/Packages/lesiontracker/client/components/activeEntry/activeEntry.styl b/Packages/lesiontracker/client/components/activeEntry/activeEntry.styl index e179b9e1f..51fae12f7 100644 --- a/Packages/lesiontracker/client/components/activeEntry/activeEntry.styl +++ b/Packages/lesiontracker/client/components/activeEntry/activeEntry.styl @@ -1,5 +1,6 @@ #entrySignIn.entryPage, -#entrySignUp.entryPage +#entrySignUp.entryPage, +#changePassword .wrapper-auth .title-auth color: white