/// <summary> /// Checks that a user submitted password conforms to any password rules including length, /// special characters, alphanumeric, etc as well as matching their confirmation entry. /// </summary> /// <param name="request">The request object containing the password to check, and optionally the username to ensure the password doesnt contain the username</param> /// <returns>Response object where IsSuccessful is True if the password meets complexity requirements, false if it doesnt.</returns> public CheckPasswordComplexityResponse CheckPasswordComplexity(CheckPasswordComplexityRequest request) { // //Validate the parameters // if (request == null) { return(new CheckPasswordComplexityResponse() { IsSuccessful = false, Message = "An invalid request was made to check password complexity." }); } // //Reject if the password has fewer than the minimum number of characters // if (String.IsNullOrEmpty(request.Password) || request.Password.Length < PASSWORD_MIN_LENGTH) { return(new CheckPasswordComplexityResponse() { IsSuccessful = false, Message = String.Format("Password must be at least {0} characters long.", PASSWORD_MIN_LENGTH) }); } // //Reject if the password contains the username // if (!String.IsNullOrEmpty(request.UserName) && request.Password.Contains(request.UserName)) { return(new CheckPasswordComplexityResponse() { IsSuccessful = false, Message = String.Format("Password cannot contain your username.") }); } // //Password must contain a digit // if (!System.Text.RegularExpressions.Regex.IsMatch(request.Password, @"\d")) { return(new CheckPasswordComplexityResponse() { IsSuccessful = false, Message = String.Format("Password must contain at least one number.") }); } // //Password must contain a capital letter // if (!System.Text.RegularExpressions.Regex.IsMatch(request.Password, @"[A-Z]")) { return(new CheckPasswordComplexityResponse() { IsSuccessful = false, Message = String.Format("Password must contain at least one capital letter.") }); } // //Password is valid if we get here // return(new CheckPasswordComplexityResponse() { IsSuccessful = true, Message = null }); }
/// <summary> /// Change a users password /// </summary> /// <param name="request"></param> /// <returns></returns> public ChangePasswordResponse ChangePassword(ChangePasswordRequest request) { try { // //Validate the parameters // if (request == null || String.IsNullOrWhiteSpace(request.UserName)) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = "An invalid password change request was made." }); } // //Validate the new passwords are equal // if (!request.NewPassword.Equals(request.NewPasswordConfirm)) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = "The passwords you entered must match." }); } // //Validate the new passwords meets complexity requirements // if (request.CheckPasswordComplexity) { var passwordComplexityRequest = new CheckPasswordComplexityRequest() { Password = request.NewPassword, UserName = request.UserName }; var passwordComplexityResponse = CheckPasswordComplexity(passwordComplexityRequest); if (!passwordComplexityResponse.IsSuccessful) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = passwordComplexityResponse.Message }); } } // //Determine if this is for an AD user or a security user record //Get the SecurityUser Record if we have it // SecurityUser securityUser = null; ADUser adUser = null; if (request.SecurityUserId != null) { securityUser = _repository.GetAll <SecurityUser>() .FirstOrDefault(p => p.SecurityUserId == request.SecurityUserId); } // //Get the AD user if AD authentication is enabled, and we dont have a security user //or we dont have a security user active directory guid // if (DomainApplicationService.Instance.FormsAuthenticationADEnabled && (securityUser == null || securityUser.ActiveDirectoryGuid == null)) { adUser = new ADUser(request.UserName); if (adUser == null || !adUser.ValidUser) { adUser = null; } } else if (DomainApplicationService.Instance.FormsAuthenticationADEnabled && securityUser.ActiveDirectoryGuid != null) { adUser = new ADUser(securityUser.ActiveDirectoryGuid.Value); if (adUser == null || !adUser.ValidUser) { adUser = null; } } // //Ensure we found a user account to reset a password for // if (securityUser == null && adUser == null) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = "A valid user could not be found to reset the password for." }); } // //Ensure the user account is active and not locked and its password can be reset // // if (request.CheckIfUserPasswordCanBeChanged) { var canUserPasswordBeChangedRequest = new CanUserPasswordBeChangedRequest() { SecurityUser = securityUser, ADUser = adUser, AuthenticationMethod = request.AuthenticationMethod }; var canUserPasswordBeChangedResponse = CanUserPasswordBeChanged(canUserPasswordBeChangedRequest); if (!canUserPasswordBeChangedResponse.IsSuccessful) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = String.Format( "{0} Please contact support to have the password changed.", canUserPasswordBeChangedResponse.Message) }); } } DateTime?newPasswordExpirationDate = null; var passwordChanged = false; // //If AD user, connect to AD and reset the users password //Ensure the user is allowed to reset their password // if (adUser != null && (securityUser == null || request.AuthenticationMethod == AuthenticationMethods.ActiveDirectory.ToString())) { adUser.ChangePassword(request.NewPassword); newPasswordExpirationDate = adUser.PasswordExpiryDate; passwordChanged = true; } // //If Security User, then reset the users password there //Generate a new passwordhash, salt, and update the password last changed date as well as password expiration date //Store the users current password in the password history table if its a SecurityUser record. // else if (securityUser != null && (request.AuthenticationMethod == null || request.AuthenticationMethod == AuthenticationMethods.SecurityUser.ToString())) { // //Ensure the users current password matches what they typed into the screen // if (request.CheckCurrentPassword) { if (securityUser.PasswordHash != SHA256Hash.HashValue(request.CurrentPassword, securityUser.PasswordSalt)) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = "An invalid current password was entered." }); } } // //Enforce password history, where a password cannot be one of the previously used passwords. // if (request.EnforcePasswordHistory) { // //Ensure the new password is not the current password // if (securityUser.PasswordHash == SHA256Hash.HashValue(request.NewPassword, securityUser.PasswordSalt)) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = "The new password cannot be the same as the current password." }); } // //Validate that the new password is not in the password history //as a previously used password // var passwordHistoryRecordsToCheck = ApplicationService.Instance.PasswordHistoryRecordsToCheckOnPasswordChange; if (passwordHistoryRecordsToCheck > 0) { var passwordHistory = _repository.GetAll <SecurityUserPasswordHistory>() .Where(p => p.SecurityUserId == securityUser.SecurityUserId) .OrderBy(p => p.CreateDate) .Take(passwordHistoryRecordsToCheck) .ToList(); foreach (var p in passwordHistory) { if (p.PasswordHash == SHA256Hash.HashValue(request.NewPassword, p.PasswordSalt)) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = "The new password cannot be one of the previously used passwords." }); } } } } // //Create the password history entry for the users current password // var securityUserPasswordHistory = new SecurityUserPasswordHistory() { SecurityUserId = securityUser.SecurityUserId, PasswordHash = securityUser.PasswordHash, PasswordSalt = securityUser.PasswordSalt }; _repository.Add(securityUserPasswordHistory); // //Update the security user record // securityUser.PasswordLastChangedDate = DateTime.Now; securityUser.PasswordSalt = SHA256Hash.CreateSalt(6); securityUser.PasswordHash = SHA256Hash.HashValue(request.NewPassword, securityUser.PasswordSalt); if (securityUser.PasswordNeverExpires) { securityUser.PasswordExpirationDate = null; } else { var passwordExpirationDateResponse = CalculatePasswordExpirationDate(new CalculatePasswordExpirationDateRequest()); securityUser.PasswordExpirationDate = passwordExpirationDateResponse.PasswordExpirationDate; } newPasswordExpirationDate = securityUser.PasswordExpirationDate; passwordChanged = true; } // //If for some reason the password couldnt be changed // if (!passwordChanged) { return(new ChangePasswordResponse() { IsSuccessful = false, Message = "The password could not be changed. Please report this error. No AD User or SecurityUser record could be obtained to change the password for." }); } _repository.Commit(); // //Repopulate the current users session values if needed // if (DomainSessionService.Instance != null && DomainSessionService.Instance.CurrentUser != null && request.UserName.Equals(DomainSessionService.Instance.CurrentUser.UserName)) { DomainSessionService.Instance.CurrentUser.PasswordExpirationDate = newPasswordExpirationDate; DomainSessionService.Instance.CurrentUser.PasswordLastChangedDate = DateTime.Now; } // //Send the user an email to confirm that their password has been reset // if (request.SendPasswordSuccessfullyChangedEmail) { var sendPasswordChangedEmailRequest = new SendPasswordChangedEmailRequest() { SecurityUser = securityUser, ADUser = adUser }; var sendPasswordChangedEmailResponse = SendPasswordChangedEmail(sendPasswordChangedEmailRequest); } // //Password change was successful if we got to here // return(new ChangePasswordResponse() { IsSuccessful = true, Message = null, PasswordExpirationDate = newPasswordExpirationDate }); } catch (Exception e) { LogService.Instance.Log.Error("An unhandled exception occurred changing the password. ", e); return(new ChangePasswordResponse() { IsSuccessful = false, Message = String.Format("An unhandled exception occurred changing the password. {0}", e.Message) }); } }