/// <summary> /// Returns the configuration of the membership provider used to configure change password editors /// </summary> /// <param name="membershipProvider"></param> /// <param name="userService"></param> /// <returns></returns> public static IDictionary <string, object> GetConfiguration( this MembershipProvider membershipProvider, IUserService userService) { var baseProvider = membershipProvider as MembershipProviderBase; var canReset = membershipProvider.CanResetPassword(userService); return(new Dictionary <string, object> { { "minPasswordLength", membershipProvider.MinRequiredPasswordLength }, { "enableReset", canReset }, { "enablePasswordRetrieval", membershipProvider.EnablePasswordRetrieval }, { "requiresQuestionAnswer", membershipProvider.RequiresQuestionAndAnswer }, { "allowManuallyChangingPassword", baseProvider != null && baseProvider.AllowManuallyChangingPassword } //TODO: Inject the other parameters in here to change the behavior of this control - based on the membership provider settings. }); }
/// <summary> /// Changes password for a member/user given the membership provider and the password change model /// </summary> /// <param name="username">The username of the user having their password changed</param> /// <param name="passwordModel"></param> /// <param name="membershipProvider"></param> /// <returns></returns> public Attempt <PasswordChangedModel> ChangePasswordWithMembershipProvider(string username, ChangingPasswordModel passwordModel, MembershipProvider membershipProvider) { // YES! It is completely insane how many options you have to take into account based on the membership provider. yikes! if (passwordModel == null) { throw new ArgumentNullException("passwordModel"); } if (membershipProvider == null) { throw new ArgumentNullException("membershipProvider"); } BackOfficeUserManager <BackOfficeIdentityUser> backofficeUserManager = null; var userId = -1; if (membershipProvider.IsUmbracoUsersProvider()) { backofficeUserManager = _httpContext.GetOwinContext().GetBackOfficeUserManager(); if (backofficeUserManager != null) { var profile = _userService.GetProfileByUserName(username); if (profile != null) { int.TryParse(profile.Id.ToString(), out userId); } } } //Are we resetting the password?? //TODO: I don't think this is required anymore since from 7.7 we no longer display the reset password checkbox since that didn't make sense. if (passwordModel.Reset.HasValue && passwordModel.Reset.Value) { var canReset = membershipProvider.CanResetPassword(_userService); if (canReset == false) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password reset is not enabled", new[] { "resetPassword" }) })); } if (membershipProvider.RequiresQuestionAndAnswer && passwordModel.Answer.IsNullOrWhiteSpace()) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password reset requires a password answer", new[] { "resetPassword" }) })); } //ok, we should be able to reset it try { var newPass = membershipProvider.ResetPassword( username, membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null); if (membershipProvider.IsUmbracoUsersProvider() && backofficeUserManager != null && userId >= 0) { backofficeUserManager.RaisePasswordResetEvent(userId); } //return the generated pword return(Attempt.Succeed(new PasswordChangedModel { ResetPassword = newPass })); } catch (Exception ex) { _logger.WarnWithException <PasswordChanger>("Could not reset member password", ex); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not reset password, error: " + ex.Message + " (see log for full details)", new[] { "resetPassword" }) })); } } //we're not resetting it so we need to try to change it. if (passwordModel.NewPassword.IsNullOrWhiteSpace()) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Cannot set an empty password", new[] { "value" }) })); } //This is an edge case and is only necessary for backwards compatibility: var umbracoBaseProvider = membershipProvider as MembershipProviderBase; if (umbracoBaseProvider != null && umbracoBaseProvider.AllowManuallyChangingPassword) { //this provider allows manually changing the password without the old password, so we can just do it try { var result = umbracoBaseProvider.ChangePassword(username, "", passwordModel.NewPassword); return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "value" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex) { _logger.WarnWithException <PasswordChanger>("Could not change member password", ex); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) })); } } //The provider does not support manually chaning the password but no old password supplied - need to return an error if (passwordModel.OldPassword.IsNullOrWhiteSpace() && membershipProvider.EnablePasswordRetrieval == false) { //if password retrieval is not enabled but there is no old password we cannot continue return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "oldPassword" }) })); } if (passwordModel.OldPassword.IsNullOrWhiteSpace() == false) { //if an old password is suplied try to change it try { var result = membershipProvider.ChangePassword(username, passwordModel.OldPassword, passwordModel.NewPassword); if (result && backofficeUserManager != null && userId >= 0) { backofficeUserManager.RaisePasswordChangedEvent(userId); } return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "oldPassword" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex) { _logger.WarnWithException <PasswordChanger>("Could not change member password", ex); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) })); } } if (membershipProvider.EnablePasswordRetrieval == false) { //we cannot continue if we cannot get the current password return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "oldPassword" }) })); } if (membershipProvider.RequiresQuestionAndAnswer && passwordModel.Answer.IsNullOrWhiteSpace()) { //if the question answer is required but there isn't one, we cannot continue return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the password answer", new[] { "value" }) })); } //lets try to get the old one so we can change it try { var oldPassword = membershipProvider.GetPassword( username, membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null); try { var result = membershipProvider.ChangePassword(username, oldPassword, passwordModel.NewPassword); return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password", new[] { "value" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex1) { _logger.WarnWithException <PasswordChanger>("Could not change member password", ex1); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex1.Message + " (see log for full details)", new[] { "value" }) })); } } catch (Exception ex2) { _logger.WarnWithException <PasswordChanger>("Could not retrieve member password", ex2); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex2.Message + " (see log for full details)", new[] { "value" }) })); } }
/// <summary> /// Changes password for a member/user given the membership provider and the password change model /// </summary> /// <param name="username">The username of the user having their password changed</param> /// <param name="passwordModel"></param> /// <param name="membershipProvider"></param> /// <returns></returns> public Attempt <PasswordChangedModel> ChangePasswordWithMembershipProvider(string username, ChangingPasswordModel passwordModel, MembershipProvider membershipProvider) { var umbracoBaseProvider = membershipProvider as MembershipProviderBase; // YES! It is completely insane how many options you have to take into account based on the membership provider. yikes! if (passwordModel == null) { throw new ArgumentNullException(nameof(passwordModel)); } if (membershipProvider == null) { throw new ArgumentNullException(nameof(membershipProvider)); } BackOfficeUserManager <BackOfficeIdentityUser> backofficeUserManager = null; var userId = -1; if (membershipProvider.IsUmbracoUsersProvider()) { backofficeUserManager = _httpContext.GetOwinContext().GetBackOfficeUserManager(); if (backofficeUserManager != null) { var profile = _userService.GetProfileByUserName(username); if (profile != null) { int.TryParse(profile.Id.ToString(), out userId); } } } //Are we resetting the password? //This flag indicates that either an admin user is changing another user's password without knowing the original password // or that the password needs to be reset to an auto-generated one. if (passwordModel.Reset.HasValue && passwordModel.Reset.Value) { //if a new password is supplied then it's an admin user trying to change another user's password without knowing the original password //this is only possible when using a membership provider if the membership provider supports AllowManuallyChangingPassword if (passwordModel.NewPassword.IsNullOrWhiteSpace() == false) { if (umbracoBaseProvider != null && umbracoBaseProvider.AllowManuallyChangingPassword) { //this provider allows manually changing the password without the old password, so we can just do it try { var result = umbracoBaseProvider.ChangePassword(username, string.Empty, passwordModel.NewPassword); if (result && backofficeUserManager != null && userId >= 0) { backofficeUserManager.RaisePasswordChangedEvent(userId); } return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "value" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex) { _logger.Warn <PasswordChanger>("Could not change member password", ex); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) })); } } else { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Provider does not support manually changing passwords", new[] { "value" }) })); } } //we've made it here which means we need to generate a new password var canReset = membershipProvider.CanResetPassword(_userService); if (canReset == false) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password reset is not enabled", new[] { "resetPassword" }) })); } if (membershipProvider.RequiresQuestionAndAnswer && passwordModel.Answer.IsNullOrWhiteSpace()) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password reset requires a password answer", new[] { "resetPassword" }) })); } //ok, we should be able to reset it try { var newPass = membershipProvider.ResetPassword( username, membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null); if (membershipProvider.IsUmbracoUsersProvider() && backofficeUserManager != null && userId >= 0) { backofficeUserManager.RaisePasswordResetEvent(userId); } //return the generated pword return(Attempt.Succeed(new PasswordChangedModel { ResetPassword = newPass })); } catch (Exception ex) { _logger.Warn <PasswordChanger>(ex, "Could not reset member password"); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not reset password, error: " + ex.Message + " (see log for full details)", new[] { "resetPassword" }) })); } } //we're not resetting it so we need to try to change it. if (passwordModel.NewPassword.IsNullOrWhiteSpace()) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Cannot set an empty password", new[] { "value" }) })); } //without being able to retrieve the original password, //we cannot arbitrarily change the password without knowing the old one and no old password was supplied - need to return an error if (passwordModel.OldPassword.IsNullOrWhiteSpace() && membershipProvider.EnablePasswordRetrieval == false) { //if password retrieval is not enabled but there is no old password we cannot continue return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "oldPassword" }) })); } if (passwordModel.OldPassword.IsNullOrWhiteSpace() == false) { //if an old password is supplied try to change it try { var result = membershipProvider.ChangePassword(username, passwordModel.OldPassword, passwordModel.NewPassword); if (result && backofficeUserManager != null && userId >= 0) { backofficeUserManager.RaisePasswordChangedEvent(userId); } return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "oldPassword" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex) { _logger.Warn <PasswordChanger>(ex, "Could not change member password"); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) })); } } if (membershipProvider.EnablePasswordRetrieval == false) { //we cannot continue if we cannot get the current password return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "oldPassword" }) })); } if (membershipProvider.RequiresQuestionAndAnswer && passwordModel.Answer.IsNullOrWhiteSpace()) { //if the question answer is required but there isn't one, we cannot continue return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the password answer", new[] { "value" }) })); } //lets try to get the old one so we can change it try { var oldPassword = membershipProvider.GetPassword( username, membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null); try { var result = membershipProvider.ChangePassword(username, oldPassword, passwordModel.NewPassword); return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password", new[] { "value" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex1) { _logger.Warn <PasswordChanger>(ex1, "Could not change member password"); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex1.Message + " (see log for full details)", new[] { "value" }) })); } } catch (Exception ex2) { _logger.Warn <PasswordChanger>(ex2, "Could not retrieve member password"); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex2.Message + " (see log for full details)", new[] { "value" }) })); } }
/// <summary> /// Changes password for a member/user given the membership provider and the password change model /// </summary> /// <param name="username"></param> /// <param name="passwordModel"></param> /// <param name="membershipProvider"></param> /// <returns></returns> public virtual Attempt <PasswordChangedModel> ChangePassword(string username, ChangingPasswordModel passwordModel, MembershipProvider membershipProvider) { // YES! It is completely insane how many options you have to take into account based on the membership provider. yikes! if (passwordModel == null) { throw new ArgumentNullException("passwordModel"); } if (membershipProvider == null) { throw new ArgumentNullException("membershipProvider"); } //Are we resetting the password?? if (passwordModel.Reset.HasValue && passwordModel.Reset.Value) { var canReset = membershipProvider.CanResetPassword(_applicationContext.Services.UserService); if (canReset == false) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password reset is not enabled", new[] { "resetPassword" }) })); } if (membershipProvider.RequiresQuestionAndAnswer && passwordModel.Answer.IsNullOrWhiteSpace()) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password reset requires a password answer", new[] { "resetPassword" }) })); } //ok, we should be able to reset it try { var newPass = membershipProvider.ResetPassword( username, membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null); //return the generated pword return(Attempt.Succeed(new PasswordChangedModel { ResetPassword = newPass })); } catch (Exception ex) { LogHelper.WarnWithException <WebSecurity>("Could not reset member password", ex); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not reset password, error: " + ex.Message + " (see log for full details)", new[] { "resetPassword" }) })); } } //we're not resetting it so we need to try to change it. if (passwordModel.NewPassword.IsNullOrWhiteSpace()) { return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Cannot set an empty password", new[] { "value" }) })); } //This is an edge case and is only necessary for backwards compatibility: var umbracoBaseProvider = membershipProvider as MembershipProviderBase; if (umbracoBaseProvider != null && umbracoBaseProvider.AllowManuallyChangingPassword) { //this provider allows manually changing the password without the old password, so we can just do it try { var result = umbracoBaseProvider.ChangePassword(username, "", passwordModel.NewPassword); return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "value" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex) { LogHelper.WarnWithException <WebSecurity>("Could not change member password", ex); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) })); } } //The provider does not support manually chaning the password but no old password supplied - need to return an error if (passwordModel.OldPassword.IsNullOrWhiteSpace() && membershipProvider.EnablePasswordRetrieval == false) { //if password retrieval is not enabled but there is no old password we cannot continue return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "value" }) })); } if (passwordModel.OldPassword.IsNullOrWhiteSpace() == false) { //if an old password is suplied try to change it try { var result = membershipProvider.ChangePassword(username, passwordModel.OldPassword, passwordModel.NewPassword); return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "value" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex) { LogHelper.WarnWithException <WebSecurity>("Could not change member password", ex); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) })); } } if (membershipProvider.EnablePasswordRetrieval == false) { //we cannot continue if we cannot get the current password return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "value" }) })); } if (membershipProvider.RequiresQuestionAndAnswer && passwordModel.Answer.IsNullOrWhiteSpace()) { //if the question answer is required but there isn't one, we cannot continue return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the password answer", new[] { "value" }) })); } //lets try to get the old one so we can change it try { var oldPassword = membershipProvider.GetPassword( username, membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null); try { var result = membershipProvider.ChangePassword(username, oldPassword, passwordModel.NewPassword); return(result == false ? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password", new[] { "value" }) }) : Attempt.Succeed(new PasswordChangedModel())); } catch (Exception ex1) { LogHelper.WarnWithException <WebSecurity>("Could not change member password", ex1); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex1.Message + " (see log for full details)", new[] { "value" }) })); } } catch (Exception ex2) { LogHelper.WarnWithException <WebSecurity>("Could not retrieve member password", ex2); return(Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex2.Message + " (see log for full details)", new[] { "value" }) })); } }