/// <summary> /// Changes the users password /// </summary> /// <param name="data"></param> /// <returns> /// If the password is being reset it will return the newly reset password, otherwise will return an empty value /// </returns> public ModelWithNotifications<string> PostChangePassword(ChangingPasswordModel data) { var userProvider = Membership.Providers[UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider]; if (userProvider == null) { throw new InvalidOperationException("No membership provider found with the name " + UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider); } //TODO: WE need to support this! - requires UI updates, etc... if (userProvider.RequiresQuestionAndAnswer) { throw new NotSupportedException("Currently the user editor does not support providers that have RequiresQuestionAndAnswer specified"); } var passwordChangeResult = Security.ChangePassword(Security.CurrentUser.Username, data, userProvider); if (passwordChangeResult.Success) { //even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword var result = new ModelWithNotifications<string>(passwordChangeResult.Result.ResetPassword); result.AddSuccessNotification(ui.Text("user", "password"), ui.Text("user", "passwordChanged")); return result; } //it wasn't successful, so add the change error to the model state, we've name the property alias _umb_password on the form // so that is why it is being used here. ModelState.AddPropertyError( passwordChangeResult.Result.ChangeError, string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); }
/// <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> /// <remarks> /// YES! It is completely insane how many options you have to take into account based on the membership provider. yikes! /// </remarks> internal Attempt<PasswordChangedModel> ChangePassword(string username, ChangingPasswordModel passwordModel, MembershipProvider membershipProvider) { 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) { if (membershipProvider.EnablePasswordReset == 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" }) }); } }