diff --git a/src/Umbraco.Core/Security/BackOfficeUserManager.cs b/src/Umbraco.Core/Security/BackOfficeUserManager.cs
index ad22c1426e..993f0671f3 100644
--- a/src/Umbraco.Core/Security/BackOfficeUserManager.cs
+++ b/src/Umbraco.Core/Security/BackOfficeUserManager.cs
@@ -137,7 +137,9 @@ namespace Umbraco.Core.Security
/// Initializes the user manager with the correct options
///
///
- ///
+ ///
+ /// The for the users called UsersMembershipProvider
+ ///
///
///
protected void InitUserManager(
@@ -153,11 +155,10 @@ namespace Umbraco.Core.Security
};
// Configure validation logic for passwords
- var provider = MembershipProviderExtensions.GetUsersMembershipProvider();
- manager.PasswordValidator = new MembershipProviderPasswordValidator(provider);
+ manager.PasswordValidator = new MembershipProviderPasswordValidator(membershipProvider);
//use a custom hasher based on our membership provider
- manager.PasswordHasher = new MembershipPasswordHasher(membershipProvider);
+ manager.PasswordHasher = new MembershipProviderPasswordHasher(membershipProvider);
if (dataProtectionProvider != null)
{
diff --git a/src/Umbraco.Core/Security/MembershipPasswordHasher.cs b/src/Umbraco.Core/Security/MembershipPasswordHasher.cs
deleted file mode 100644
index 56daa3efdd..0000000000
--- a/src/Umbraco.Core/Security/MembershipPasswordHasher.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Microsoft.AspNet.Identity;
-
-namespace Umbraco.Core.Security
-{
- ///
- /// A custom password hasher that conforms to the current password hashing done in Umbraco
- ///
- internal class MembershipPasswordHasher : IPasswordHasher
- {
- private readonly MembershipProviderBase _provider;
-
- public MembershipPasswordHasher(MembershipProviderBase provider)
- {
- _provider = provider;
- }
-
- public string HashPassword(string password)
- {
- return _provider.HashPasswordForStorage(password);
- }
-
- public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
- {
- return _provider.VerifyPassword(providedPassword, hashedPassword)
- ? PasswordVerificationResult.Success
- : PasswordVerificationResult.Failed;
- }
-
-
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Security/MembershipProviderPasswordHasher.cs b/src/Umbraco.Core/Security/MembershipProviderPasswordHasher.cs
new file mode 100644
index 0000000000..01f62ca51b
--- /dev/null
+++ b/src/Umbraco.Core/Security/MembershipProviderPasswordHasher.cs
@@ -0,0 +1,47 @@
+using System;
+using Microsoft.AspNet.Identity;
+
+namespace Umbraco.Core.Security
+{
+ public interface IUserAwarePasswordHasher
+ where TKey : IEquatable
+ {
+ string HashPassword(TKey id, string password);
+ string VerifyHashedPassword(TKey id, string hashedPassword, string providedPassword);
+ }
+
+ public interface IMembershipProviderPasswordHasher : IPasswordHasher
+ {
+ MembershipProviderBase MembershipProvider { get; }
+ }
+
+ ///
+ /// A custom password hasher that conforms to the password hashing done with membership providers
+ ///
+ public class MembershipProviderPasswordHasher : IMembershipProviderPasswordHasher
+ {
+ ///
+ /// Exposes the underlying MembershipProvider
+ ///
+ public MembershipProviderBase MembershipProvider { get; private set; }
+
+ public MembershipProviderPasswordHasher(MembershipProviderBase provider)
+ {
+ MembershipProvider = provider;
+ }
+
+ public string HashPassword(string password)
+ {
+ return MembershipProvider.HashPasswordForStorage(password);
+ }
+
+ public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
+ {
+ return MembershipProvider.VerifyPassword(providedPassword, hashedPassword)
+ ? PasswordVerificationResult.Success
+ : PasswordVerificationResult.Failed;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 0edbdc77cf..4d46e6c319 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -663,7 +663,7 @@
-
+
diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs
index f61e11a791..f38a9965cd 100644
--- a/src/Umbraco.Web/Editors/AuthenticationController.cs
+++ b/src/Umbraco.Web/Editors/AuthenticationController.cs
@@ -56,7 +56,9 @@ namespace Umbraco.Web.Editors
///
[WebApi.UmbracoAuthorize(requireApproval: false)]
public IDictionary GetMembershipProviderConfig()
- {
+ {
+ //TODO: Check if the current PasswordValidator is an IMembershipProviderPasswordValidator, if
+ //it's not than we should return some generic defaults
var provider = Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider();
return provider.GetConfiguration(Services.UserService);
}
diff --git a/src/Umbraco.Web/Editors/CurrentUserController.cs b/src/Umbraco.Web/Editors/CurrentUserController.cs
index 8db46ec1e8..a374c5579d 100644
--- a/src/Umbraco.Web/Editors/CurrentUserController.cs
+++ b/src/Umbraco.Web/Editors/CurrentUserController.cs
@@ -86,9 +86,10 @@ namespace Umbraco.Web.Editors
///
/// If the password is being reset it will return the newly reset password, otherwise will return an empty value
///
- public ModelWithNotifications PostChangePassword(ChangingPasswordModel data)
+ public async Task> PostChangePassword(ChangingPasswordModel data)
{
- var passwordChangeResult = PasswordChangeControllerHelper.ChangePassword(Security.CurrentUser, data, ModelState, Members);
+ var passwordChanger = new PasswordChanger(Logger, Services.UserService);
+ var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(Security.CurrentUser, data, ModelState, UserManager);
if (passwordChangeResult.Success)
{
diff --git a/src/Umbraco.Web/Editors/PasswordChangeControllerHelper.cs b/src/Umbraco.Web/Editors/PasswordChangeControllerHelper.cs
deleted file mode 100644
index 899e0eb9da..0000000000
--- a/src/Umbraco.Web/Editors/PasswordChangeControllerHelper.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System;
-using System.Linq;
-using System.Web.Http.ModelBinding;
-using Umbraco.Core;
-using Umbraco.Core.Models.Membership;
-using Umbraco.Web.Models;
-using Umbraco.Web.Security;
-
-namespace Umbraco.Web.Editors
-{
- internal class PasswordChangeControllerHelper
- {
-
- public static Attempt ChangePassword(
- IUser currentUser,
- ChangingPasswordModel data,
- ModelStateDictionary modelState,
- MembershipHelper membersHelper)
- {
- var userProvider = Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider();
-
- if (userProvider.RequiresQuestionAndAnswer)
- {
- throw new NotSupportedException("Currently the user editor does not support providers that have RequiresQuestionAndAnswer specified");
- }
-
- var passwordChangeResult = membersHelper.ChangePassword(currentUser.Username, data, userProvider);
- if (passwordChangeResult.Success == false)
- {
- //it wasn't successful, so add the change error to the model state
- var fieldName = passwordChangeResult.Result.ChangeError.MemberNames.FirstOrDefault() ?? "password";
- modelState.AddModelError(fieldName,
- passwordChangeResult.Result.ChangeError.ErrorMessage);
- }
-
- return passwordChangeResult;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Editors/PasswordChanger.cs b/src/Umbraco.Web/Editors/PasswordChanger.cs
new file mode 100644
index 0000000000..ffd5a9b0fd
--- /dev/null
+++ b/src/Umbraco.Web/Editors/PasswordChanger.cs
@@ -0,0 +1,246 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Web.Http.ModelBinding;
+using System.Web.Security;
+using Microsoft.AspNet.Identity;
+using umbraco.cms.businesslogic.packager;
+using Umbraco.Core;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Models.Identity;
+using Umbraco.Core.Security;
+using Umbraco.Core.Services;
+using Umbraco.Web.Models;
+using Umbraco.Web.Security;
+using IUser = Umbraco.Core.Models.Membership.IUser;
+
+namespace Umbraco.Web.Editors
+{
+ internal class PasswordChanger
+ {
+ private readonly ILogger _logger;
+ private readonly IUserService _userService;
+
+ public PasswordChanger(ILogger logger, IUserService userService)
+ {
+ _logger = logger;
+ _userService = userService;
+ }
+
+ public async Task> ChangePasswordWithIdentityAsync(
+ IUser currentUser,
+ ChangingPasswordModel passwordModel,
+ ModelStateDictionary modelState,
+ BackOfficeUserManager userMgr)
+ {
+ if (passwordModel == null) throw new ArgumentNullException("passwordModel");
+ if (userMgr == null) throw new ArgumentNullException("userMgr");
+
+ //check if this identity implementation is powered by an underlying membership provider (it will be in most cases)
+ var membershipPasswordHasher = userMgr.PasswordHasher as IMembershipProviderPasswordHasher;
+
+ //check if this identity implementation is powered by an IUserAwarePasswordHasher (it will be by default in 7.7+ but not for upgrades)
+ var userAwarePasswordHasher = userMgr.PasswordHasher as IUserAwarePasswordHasher;
+
+ if (membershipPasswordHasher != null && userAwarePasswordHasher == null)
+ {
+ //if this isn't using an IUserAwarePasswordHasher, then fallback to the old way
+ if (membershipPasswordHasher.MembershipProvider.RequiresQuestionAndAnswer)
+ throw new NotSupportedException("Currently the user editor does not support providers that have RequiresQuestionAndAnswer specified");
+ return ChangePasswordWithMembershipProvider(currentUser.Username, passwordModel, membershipPasswordHasher.MembershipProvider);
+ }
+
+ //get the real password validator, thsi should not be null but in some very rare cases it could be, in which case
+ //we need to create a default password validator to use since we have no idea what it actually is or what it's rules are
+ //this is an Edge Case!
+ var passwordValidator = userMgr.PasswordValidator as PasswordValidator
+ ?? (membershipPasswordHasher != null
+ ? new MembershipProviderPasswordValidator(membershipPasswordHasher.MembershipProvider)
+ : new PasswordValidator());
+
+ //Are we resetting the password??
+ if (passwordModel.Reset.HasValue && passwordModel.Reset.Value)
+ {
+ //ok, we should be able to reset it
+ var resetToken = await userMgr.GeneratePasswordResetTokenAsync(currentUser.Id);
+ var newPass = Membership.GeneratePassword(passwordValidator.RequiredLength, passwordValidator.RequireNonLetterOrDigit ? 2 : 0);
+ var resetResult = await userMgr.ResetPasswordAsync(currentUser.Id, resetToken, newPass);
+
+ if (resetResult.Succeeded == false)
+ {
+ var errors = string.Join(". ", resetResult.Errors);
+ _logger.Warn(string.Format("Could not reset member password {0}", errors));
+ return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not reset password, errors: " + errors, new[] { "resetPassword" }) });
+ }
+
+ return Attempt.Succeed(new PasswordChangedModel { ResetPassword = newPass });
+ }
+
+ //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" }) });
+ }
+
+ //we cannot arbitrarily change the password without knowing the old one and no old password was supplied - need to return an error
+ //TODO: What if the current user is admin? We should allow manually changing then?
+ if (passwordModel.OldPassword.IsNullOrWhiteSpace())
+ {
+ //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
+ var changeResult = await userMgr.ChangePasswordAsync(currentUser.Id, passwordModel.OldPassword, passwordModel.NewPassword);
+ if (changeResult.Succeeded == false)
+ {
+ var errors = string.Join(". ", changeResult.Errors);
+ _logger.Warn(string.Format("Could not change member password {0}", errors));
+ return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, errors: " + errors, new[] { "value" }) });
+ }
+ return Attempt.Succeed(new PasswordChangedModel());
+ }
+
+ //We shouldn't really get here
+ return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid information supplied", new[] { "value" }) });
+ }
+
+ ///
+ /// Changes password for a member/user given the membership provider and the password change model
+ ///
+ ///
+ ///
+ ///
+ ///
+ public Attempt 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");
+
+ //Are we resetting the password??
+ 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);
+
+ //return the generated pword
+ return Attempt.Succeed(new PasswordChangedModel { ResetPassword = newPass });
+ }
+ catch (Exception ex)
+ {
+ _logger.WarnWithException("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("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);
+ 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("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("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("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" }) });
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs
index 0039128e86..9164ea8630 100644
--- a/src/Umbraco.Web/Editors/UsersController.cs
+++ b/src/Umbraco.Web/Editors/UsersController.cs
@@ -404,7 +404,7 @@ namespace Umbraco.Web.Editors
///
///
///
- public UserDisplay PostSaveUser(UserSave userSave)
+ public async Task PostSaveUser(UserSave userSave)
{
if (userSave == null) throw new ArgumentNullException("userSave");
@@ -460,7 +460,9 @@ namespace Umbraco.Web.Editors
var resetPasswordValue = string.Empty;
if (userSave.ChangePassword != null)
{
- var passwordChangeResult = PasswordChangeControllerHelper.ChangePassword(found, userSave.ChangePassword, ModelState, Members);
+ var passwordChanger = new PasswordChanger(Logger, Services.UserService);
+
+ var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(found, userSave.ChangePassword, ModelState, UserManager);
if (passwordChangeResult.Success)
{
//depending on how the provider is configured, the password may be reset so let's store that for later
diff --git a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs
index 7a6a54f9e7..2d0daf1aa9 100644
--- a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs
+++ b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs
@@ -32,6 +32,7 @@ namespace Umbraco.Web.Install.InstallSteps
_applicationContext = applicationContext;
}
+ //TODO: Change all logic in this step to use ASP.NET Identity NOT MembershipProviders
private MembershipProvider CurrentProvider
{
get
diff --git a/src/Umbraco.Web/Security/MembershipHelper.cs b/src/Umbraco.Web/Security/MembershipHelper.cs
index 81487c41d9..43d3c55c65 100644
--- a/src/Umbraco.Web/Security/MembershipHelper.cs
+++ b/src/Umbraco.Web/Security/MembershipHelper.cs
@@ -13,6 +13,7 @@ using Umbraco.Core.Security;
using Umbraco.Web.Models;
using Umbraco.Web.PublishedCache;
using Umbraco.Core.Cache;
+using Umbraco.Web.Editors;
using Umbraco.Web.Security.Providers;
using MPE = global::Umbraco.Core.Security.MembershipProviderExtensions;
@@ -655,128 +656,8 @@ namespace Umbraco.Web.Security
///
public virtual Attempt 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("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("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);
- 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)
- {
- LogHelper.WarnWithException("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)
- {
- LogHelper.WarnWithException("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("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" }) });
- }
+ var passwordChanger = new PasswordChanger(_applicationContext.ProfilingLogger.Logger, _applicationContext.Services.UserService);
+ return passwordChanger.ChangePasswordWithMembershipProvider(username, passwordModel, membershipProvider);
}
///
diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs
index e4a29bd6cc..e46250bed8 100644
--- a/src/Umbraco.Web/Security/WebSecurity.cs
+++ b/src/Umbraco.Web/Security/WebSecurity.cs
@@ -170,10 +170,14 @@ namespace Umbraco.Web.Security
///
///
///
+ ///
+ /// This uses ASP.NET Identity to perform the validation
+ ///
public virtual bool ValidateBackOfficeCredentials(string username, string password)
{
- var membershipProvider = Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider();
- return membershipProvider != null && membershipProvider.ValidateUser(username, password);
+ var backofficeuser = Mapper.Map(CurrentUser);
+ backofficeuser.UserName = username;
+ return UserManager.CheckPasswordAsync(backofficeuser, password).Result;
}
///
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index afa4790262..29f4d04f26 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -333,7 +333,7 @@
-
+