From 6410a83ca8db6f4c014a422ef70610db627520b9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 3 Dec 2019 14:16:05 +1100 Subject: [PATCH 1/4] Fixes issue with empty connection string on startup --- src/Umbraco.Configuration/ConnectionStrings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Configuration/ConnectionStrings.cs b/src/Umbraco.Configuration/ConnectionStrings.cs index 1842ff6627..707f58c7b7 100644 --- a/src/Umbraco.Configuration/ConnectionStrings.cs +++ b/src/Umbraco.Configuration/ConnectionStrings.cs @@ -13,7 +13,7 @@ namespace Umbraco.Core.Configuration get { var settings = ConfigurationManager.ConnectionStrings[key]; - + if (settings == null) return null; return new ConfigConnectionString(settings.ConnectionString, settings.ProviderName, settings.Name); } } From d7fa5f0b66eaa270786c574193466f83c998ac05 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 3 Dec 2019 15:28:55 +1100 Subject: [PATCH 2/4] Removes membership providers stuff from back office, removes all old legacy rules for passwords and membership providers. --- .../IMemberPasswordConfiguration.cs | 9 + .../IUserPasswordConfiguration.cs | 1 - .../Security/IPasswordGenerator.cs | 17 - .../Security/PasswordGenerator.cs | 22 +- src/Umbraco.Configuration/ConfigsFactory.cs | 10 +- src/Umbraco.Core/Composing/Current.cs | 3 - .../Runtime/CoreInitialComposer.cs | 1 - src/Umbraco.Core/Security/PasswordSecurity.cs | 109 ++++-- .../Membership/MembershipProviderBaseTests.cs | 34 -- .../UmbracoServiceMembershipProviderTests.cs | 2 +- .../Routing/RenderRouteHandlerTests.cs | 2 +- .../Security/PasswordSecurityTests.cs | 6 +- .../TestControllerActivatorBase.cs | 2 +- .../Testing/TestingTests/MockTests.cs | 4 +- .../AuthenticationControllerTests.cs | 2 +- .../Web/Mvc/SurfaceControllerTests.cs | 2 +- .../application/umblogin.directive.js | 2 +- .../users/changepassword.directive.js | 32 +- .../src/common/resources/auth.resource.js | 14 +- .../common/overlays/user/user.controller.js | 36 +- .../components/users/change-password.html | 19 +- .../views/member/member.edit.controller.js | 7 - .../changepassword.controller.js | 20 +- .../src/views/users/user.controller.js | 25 +- .../Editors/AuthenticationController.cs | 4 +- .../Editors/CurrentUserController.cs | 9 +- src/Umbraco.Web/Editors/MemberController.cs | 367 ++++-------------- src/Umbraco.Web/Editors/PasswordChanger.cs | 236 +++-------- src/Umbraco.Web/Editors/UsersController.cs | 2 +- .../Models/ChangingPasswordModel.cs | 30 -- .../Models/ContentEditing/MemberSave.cs | 2 + .../Mapping/MemberTabsAndPropertiesMapper.cs | 7 +- .../PasswordConfigurationExtensions.cs | 15 +- .../Security/AppBuilderExtensions.cs | 12 +- .../Security/BackOfficeUserManager.cs | 55 +-- src/Umbraco.Web/Security/MembershipHelper.cs | 5 +- .../Security/MembershipProviderBase.cs | 35 +- .../Security/MembershipProviderExtensions.cs | 34 -- .../Providers/UmbracoMembershipProvider.cs | 14 +- src/Umbraco.Web/UmbracoDefaultOwinStartup.cs | 4 +- 40 files changed, 328 insertions(+), 884 deletions(-) create mode 100644 src/Umbraco.Abstractions/Configuration/IMemberPasswordConfiguration.cs delete mode 100644 src/Umbraco.Abstractions/Security/IPasswordGenerator.cs diff --git a/src/Umbraco.Abstractions/Configuration/IMemberPasswordConfiguration.cs b/src/Umbraco.Abstractions/Configuration/IMemberPasswordConfiguration.cs new file mode 100644 index 0000000000..a7c956a337 --- /dev/null +++ b/src/Umbraco.Abstractions/Configuration/IMemberPasswordConfiguration.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Configuration +{ + /// + /// The password configuration for members + /// + public interface IMemberPasswordConfiguration : IPasswordConfiguration + { + } +} diff --git a/src/Umbraco.Abstractions/Configuration/IUserPasswordConfiguration.cs b/src/Umbraco.Abstractions/Configuration/IUserPasswordConfiguration.cs index 04af69c68c..ca9a7f3271 100644 --- a/src/Umbraco.Abstractions/Configuration/IUserPasswordConfiguration.cs +++ b/src/Umbraco.Abstractions/Configuration/IUserPasswordConfiguration.cs @@ -5,6 +5,5 @@ /// public interface IUserPasswordConfiguration : IPasswordConfiguration { - } } diff --git a/src/Umbraco.Abstractions/Security/IPasswordGenerator.cs b/src/Umbraco.Abstractions/Security/IPasswordGenerator.cs deleted file mode 100644 index 3977ec3cf6..0000000000 --- a/src/Umbraco.Abstractions/Security/IPasswordGenerator.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Umbraco.Core.Configuration; - -namespace Umbraco.Core.Security -{ - /// - /// Generates a password - /// - public interface IPasswordGenerator - { - /// - /// Generates a password - /// - /// - /// - string GeneratePassword(IPasswordConfiguration passwordConfiguration); - } -} diff --git a/src/Umbraco.Abstractions/Security/PasswordGenerator.cs b/src/Umbraco.Abstractions/Security/PasswordGenerator.cs index 2dca396384..d8e18a8146 100644 --- a/src/Umbraco.Abstractions/Security/PasswordGenerator.cs +++ b/src/Umbraco.Abstractions/Security/PasswordGenerator.cs @@ -11,28 +11,34 @@ namespace Umbraco.Core.Security /// /// This uses logic copied from the old MembershipProvider.GeneratePassword logic /// - public class PasswordGenerator : IPasswordGenerator + public class PasswordGenerator { - public string GeneratePassword(IPasswordConfiguration passwordConfiguration) + private readonly IPasswordConfiguration _passwordConfiguration; + + public PasswordGenerator(IPasswordConfiguration passwordConfiguration) + { + _passwordConfiguration = passwordConfiguration; + } + public string GeneratePassword() { var password = PasswordStore.GeneratePassword( - passwordConfiguration.RequiredLength, - passwordConfiguration.RequireNonLetterOrDigit ? 2 : 0); + _passwordConfiguration.RequiredLength, + _passwordConfiguration.RequireNonLetterOrDigit ? 2 : 0); var random = new Random(); var passwordChars = password.ToCharArray(); - if (passwordConfiguration.RequireDigit && passwordChars.ContainsAny(Enumerable.Range(48, 58).Select(x => (char)x))) + if (_passwordConfiguration.RequireDigit && passwordChars.ContainsAny(Enumerable.Range(48, 58).Select(x => (char)x))) password += Convert.ToChar(random.Next(48, 58)); // 0-9 - if (passwordConfiguration.RequireLowercase && passwordChars.ContainsAny(Enumerable.Range(97, 123).Select(x => (char)x))) + if (_passwordConfiguration.RequireLowercase && passwordChars.ContainsAny(Enumerable.Range(97, 123).Select(x => (char)x))) password += Convert.ToChar(random.Next(97, 123)); // a-z - if (passwordConfiguration.RequireUppercase && passwordChars.ContainsAny(Enumerable.Range(65, 91).Select(x => (char)x))) + if (_passwordConfiguration.RequireUppercase && passwordChars.ContainsAny(Enumerable.Range(65, 91).Select(x => (char)x))) password += Convert.ToChar(random.Next(65, 91)); // A-Z - if (passwordConfiguration.RequireNonLetterOrDigit && passwordChars.ContainsAny(Enumerable.Range(33, 48).Select(x => (char)x))) + if (_passwordConfiguration.RequireNonLetterOrDigit && passwordChars.ContainsAny(Enumerable.Range(33, 48).Select(x => (char)x))) password += Convert.ToChar(random.Next(33, 48)); // symbols !"#$%&'()*+,-./ return password; diff --git a/src/Umbraco.Configuration/ConfigsFactory.cs b/src/Umbraco.Configuration/ConfigsFactory.cs index cc68549412..ceef2f8f5a 100644 --- a/src/Umbraco.Configuration/ConfigsFactory.cs +++ b/src/Umbraco.Configuration/ConfigsFactory.cs @@ -25,7 +25,8 @@ namespace Umbraco.Core.Configuration configs.Add("umbracoConfiguration/settings"); configs.Add("umbracoConfiguration/HealthChecks"); - configs.Add(() => new DefaultUserPasswordConfig()); + configs.Add(() => new DefaultPasswordConfig()); + configs.Add(() => new DefaultPasswordConfig()); configs.Add(() => new CoreDebug()); configs.Add(() => new ConnectionStrings()); configs.AddCoreConfigs(_ioHelper); @@ -34,9 +35,10 @@ namespace Umbraco.Core.Configuration } // Default/static user password configs - // TODO: Make this configurable somewhere - we've removed membership providers, so could be a section in the umbracosettings.config file? - // keeping in mind that we will also be removing the members membership provider so there will be 2x the same/similar configuration - internal class DefaultUserPasswordConfig : IUserPasswordConfiguration + // TODO: Make this configurable somewhere - we've removed membership providers for users, so could be a section in the umbracosettings.config file? + // keeping in mind that we will also be removing the members membership provider so there will be 2x the same/similar configuration. + // TODO: Currently it doesn't actually seem possible to replace any sub-configuration unless totally replacing the IConfigsFactory?? + internal class DefaultPasswordConfig : IUserPasswordConfiguration, IMemberPasswordConfiguration { public int RequiredLength => 12; public bool RequireNonLetterOrDigit => false; diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs index 8b5eab0139..e0cedca0ce 100644 --- a/src/Umbraco.Core/Composing/Current.cs +++ b/src/Umbraco.Core/Composing/Current.cs @@ -127,9 +127,6 @@ namespace Umbraco.Core.Composing public static IRuntimeState RuntimeState => Factory.GetInstance(); - public static IPasswordGenerator PasswordGenerator - => Factory.GetInstance(); - public static TypeLoader TypeLoader => Factory.GetInstance(); diff --git a/src/Umbraco.Core/Runtime/CoreInitialComposer.cs b/src/Umbraco.Core/Runtime/CoreInitialComposer.cs index 0a2e39592f..4b26fe6201 100644 --- a/src/Umbraco.Core/Runtime/CoreInitialComposer.cs +++ b/src/Umbraco.Core/Runtime/CoreInitialComposer.cs @@ -135,7 +135,6 @@ namespace Umbraco.Core.Runtime composition.SetCultureDictionaryFactory(); composition.Register(f => f.GetInstance().CreateDictionary(), Lifetime.Singleton); - composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Core/Security/PasswordSecurity.cs b/src/Umbraco.Core/Security/PasswordSecurity.cs index 6ffcff67de..b38e125a44 100644 --- a/src/Umbraco.Core/Security/PasswordSecurity.cs +++ b/src/Umbraco.Core/Security/PasswordSecurity.cs @@ -1,19 +1,58 @@ using System; +using System.Collections.Generic; using System.Security.Cryptography; using System.Text; +using System.Threading.Tasks; using Umbraco.Core.Configuration; namespace Umbraco.Core.Security { + /// + /// Handles password hashing and formatting + /// public class PasswordSecurity { - private readonly IPasswordConfiguration _passwordConfiguration; + public IPasswordConfiguration PasswordConfiguration { get; } + public PasswordGenerator _generator; + public ConfiguredPasswordValidator _validator; + /// + /// Constructor + /// + /// public PasswordSecurity(IPasswordConfiguration passwordConfiguration) { - _passwordConfiguration = passwordConfiguration; + PasswordConfiguration = passwordConfiguration; } + /// + /// Checks if the password passes validation rules + /// + /// + /// + public async Task>> IsValidPasswordAsync(string password) + { + if (_validator == null) + _validator = new ConfiguredPasswordValidator(PasswordConfiguration); + var result = await _validator.ValidateAsync(password); + if (result.Succeeded) + return Attempt>.Succeed(); + + return Attempt>.Fail(result.Errors); + } + + public string GeneratePassword() + { + if (_generator == null) + _generator = new PasswordGenerator(PasswordConfiguration); + return _generator.GeneratePassword(); + } + + /// + /// Returns a hashed password value used to store in a data store + /// + /// + /// public string HashPasswordForStorage(string password) { string salt; @@ -21,34 +60,34 @@ namespace Umbraco.Core.Security return FormatPasswordForStorage(hashed, salt); } - public bool VerifyPassword(string password, string hashedPassword) - { - if (string.IsNullOrWhiteSpace(hashedPassword)) throw new ArgumentException("Value cannot be null or whitespace.", "hashedPassword"); - return CheckPassword(password, hashedPassword); - } - /// /// If the password format is a hashed keyed algorithm then we will pre-pend the salt used to hash the password /// to the hashed password itself. /// + /// + /// + /// + public string FormatPasswordForStorage(string hashedPassword, string salt) + { + if (PasswordConfiguration.UseLegacyEncoding) + { + return hashedPassword; + } + + return salt + hashedPassword; + } + + /// + /// Hashes a password with a given salt + /// /// /// /// - public string FormatPasswordForStorage(string pass, string salt) - { - if (_passwordConfiguration.UseLegacyEncoding) - { - return pass; - } - - return salt + pass; - } - public string HashPassword(string pass, string salt) { //if we are doing it the old way - if (_passwordConfiguration.UseLegacyEncoding) + if (PasswordConfiguration.UseLegacyEncoding) { return LegacyEncodePassword(pass); } @@ -103,21 +142,21 @@ namespace Umbraco.Core.Security } /// - /// Checks the password. + /// Verifies if the password matches the expected hash+salt of the stored password string /// /// The password. - /// The dbPassword. + /// The value of the password stored in a data store. /// - public bool CheckPassword(string password, string dbPassword) + public bool VerifyPassword(string password, string dbPassword) { if (string.IsNullOrWhiteSpace(dbPassword)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(dbPassword)); - var storedHashedPass = StoredPassword(dbPassword, out var salt); + var storedHashedPass = ParseStoredHashPassword(dbPassword, out var salt); var hashed = HashPassword(password, salt); return storedHashedPass == hashed; } /// - /// hash a new password with a new salt + /// Create a new password hash and a new salt /// /// /// @@ -129,15 +168,15 @@ namespace Umbraco.Core.Security } /// - /// Returns the hashed password without the salt if it is hashed + /// Parses out the hashed password and the salt from the stored password string value /// /// /// returns the salt /// - public string StoredPassword(string storedString, out string salt) + public string ParseStoredHashPassword(string storedString, out string salt) { if (string.IsNullOrWhiteSpace(storedString)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(storedString)); - if (_passwordConfiguration.UseLegacyEncoding) + if (PasswordConfiguration.UseLegacyEncoding) { salt = string.Empty; return storedString; @@ -155,9 +194,14 @@ namespace Umbraco.Core.Security return Convert.ToBase64String(numArray); } + /// + /// Return the hash algorithm to use + /// + /// + /// public HashAlgorithm GetHashAlgorithm(string password) { - if (_passwordConfiguration.UseLegacyEncoding) + if (PasswordConfiguration.UseLegacyEncoding) { return new HMACSHA1 { @@ -166,12 +210,12 @@ namespace Umbraco.Core.Security }; } - if (_passwordConfiguration.HashAlgorithmType.IsNullOrWhiteSpace()) + if (PasswordConfiguration.HashAlgorithmType.IsNullOrWhiteSpace()) throw new InvalidOperationException("No hash algorithm type specified"); - var alg = HashAlgorithm.Create(_passwordConfiguration.HashAlgorithmType); + var alg = HashAlgorithm.Create(PasswordConfiguration.HashAlgorithmType); if (alg == null) - throw new InvalidOperationException($"The hash algorithm specified {_passwordConfiguration.HashAlgorithmType} cannot be resolved"); + throw new InvalidOperationException($"The hash algorithm specified {PasswordConfiguration.HashAlgorithmType} cannot be resolved"); return alg; } @@ -183,9 +227,8 @@ namespace Umbraco.Core.Security /// The encoded password. private string LegacyEncodePassword(string password) { - string encodedPassword = password; var hashAlgorith = GetHashAlgorithm(password); - encodedPassword = Convert.ToBase64String(hashAlgorith.ComputeHash(Encoding.Unicode.GetBytes(password))); + var encodedPassword = Convert.ToBase64String(hashAlgorith.ComputeHash(Encoding.Unicode.GetBytes(password))); return encodedPassword; } diff --git a/src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs b/src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs index d629479d95..92d54e9dbe 100644 --- a/src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs +++ b/src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs @@ -15,28 +15,6 @@ namespace Umbraco.Tests.Membership [UmbracoTest(WithApplication = true)] public class MembershipProviderBaseTests : UmbracoTestBase { - [Test] - public void Change_Password_Without_AllowManuallyChangingPassword_And_No_Pass_Validation() - { - var providerMock = new Mock() { CallBase = true }; - providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false); - var provider = providerMock.Object; - - Assert.Throws(() => provider.ChangePassword("test", "", "test")); - } - - [Test] - public void Change_Password_With_AllowManuallyChangingPassword_And_Invalid_Creds() - { - var providerMock = new Mock() { CallBase = true }; - providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false); - providerMock.Setup(@base => @base.ValidateUser("test", "test")).Returns(false); - var provider = providerMock.Object; - - Assert.IsFalse(provider.ChangePassword("test", "test", "test")); - - } - [Test] public void ChangePasswordQuestionAndAnswer_Without_RequiresQuestionAndAnswer() { @@ -47,18 +25,6 @@ namespace Umbraco.Tests.Membership Assert.Throws(() => provider.ChangePasswordQuestionAndAnswer("test", "test", "test", "test")); } - [Test] - public void ChangePasswordQuestionAndAnswer_Without_AllowManuallyChangingPassword_And_Invalid_Creds() - { - var providerMock = new Mock() { CallBase = true }; - providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true); - providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false); - providerMock.Setup(@base => @base.ValidateUser("test", "test")).Returns(false); - var provider = providerMock.Object; - - Assert.IsFalse(provider.ChangePasswordQuestionAndAnswer("test", "test", "test", "test")); - } - [Test] public void CreateUser_Not_Whitespace() { diff --git a/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs b/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs index 05dd7d47da..a606da9c90 100644 --- a/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs +++ b/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs @@ -106,7 +106,7 @@ namespace Umbraco.Tests.Membership Assert.AreNotEqual("test", createdMember.RawPasswordValue); string salt; - var storedPassword = provider.PasswordSecurity.StoredPassword(createdMember.RawPasswordValue, out salt); + var storedPassword = provider.PasswordSecurity.ParseStoredHashPassword(createdMember.RawPasswordValue, out salt); var hashedPassword = provider.PasswordSecurity.HashPassword("testtest$1", salt); Assert.AreEqual(hashedPassword, storedPassword); } diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index e690364dd6..463ef4339c 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -148,7 +148,7 @@ namespace Umbraco.Tests.Routing var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContextAccessor, Mock.Of(), context => { var membershipHelper = new MembershipHelper( - umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of()); + umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of()); return new CustomDocumentController(Factory.GetInstance(), umbracoContextAccessor, Factory.GetInstance(), diff --git a/src/Umbraco.Tests/Security/PasswordSecurityTests.cs b/src/Umbraco.Tests/Security/PasswordSecurityTests.cs index 6c4d700f74..9ed130a62b 100644 --- a/src/Umbraco.Tests/Security/PasswordSecurityTests.cs +++ b/src/Umbraco.Tests/Security/PasswordSecurityTests.cs @@ -40,7 +40,7 @@ namespace Umbraco.Tests.Security var hashed = passwordSecurity.HashNewPassword(pass, out salt); var storedPassword = passwordSecurity.FormatPasswordForStorage(hashed, salt); - var result = passwordSecurity.CheckPassword("ThisIsAHashedPassword", storedPassword); + var result = passwordSecurity.VerifyPassword("ThisIsAHashedPassword", storedPassword); Assert.IsTrue(result); } @@ -55,7 +55,7 @@ namespace Umbraco.Tests.Security var hashed = passwordSecurity.HashNewPassword(pass, out salt); var storedPassword = passwordSecurity.FormatPasswordForStorage(hashed, salt); - var result = passwordSecurity.CheckPassword("ThisIsAHashedPassword", storedPassword); + var result = passwordSecurity.VerifyPassword("ThisIsAHashedPassword", storedPassword); Assert.IsTrue(result); } @@ -82,7 +82,7 @@ namespace Umbraco.Tests.Security var stored = salt + "ThisIsAHashedPassword"; string initSalt; - var result = passwordSecurity.StoredPassword(stored, out initSalt); + var result = passwordSecurity.ParseStoredHashPassword(stored, out initSalt); Assert.AreEqual("ThisIsAHashedPassword", result); } diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 3dc3cefeef..1b48e83ab9 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -151,7 +151,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting urlHelper.Setup(provider => provider.GetUrl(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(UrlInfo.Url("/hello/world/1234")); - var membershipHelper = new MembershipHelper(umbCtx.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of()); + var membershipHelper = new MembershipHelper(umbCtx.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of()); var umbHelper = new UmbracoHelper(Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index 1bcbc1e420..d01721b3b9 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -71,7 +71,7 @@ namespace Umbraco.Tests.Testing.TestingTests Mock.Of(), Mock.Of(), Mock.Of(), - new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of())); + new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of())); Assert.Pass(); } @@ -103,7 +103,7 @@ namespace Umbraco.Tests.Testing.TestingTests var memberService = Mock.Of(); var memberTypeService = Mock.Of(); var membershipProvider = new MembersMembershipProvider(memberService, memberTypeService, Mock.Of()); - var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), Mock.Of(), AppCaches.Disabled, logger); + var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, logger); var umbracoHelper = new UmbracoHelper(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), membershipHelper); var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of() })); diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs index 25885d0f04..ba5e691b0e 100644 --- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs @@ -76,7 +76,7 @@ namespace Umbraco.Tests.Web.Controllers } Current.IOHelper.ForceNotHosted = true; var usersController = new AuthenticationController( - new DefaultUserPasswordConfig(), + new DefaultPasswordConfig(), Factory.GetInstance(), umbracoContextAccessor, Factory.GetInstance(), diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index c5d904fa24..0d8e9693d9 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -121,7 +121,7 @@ namespace Umbraco.Tests.Web.Mvc Mock.Of(), Mock.Of(), Mock.Of(query => query.Content(2) == content.Object), - new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of())); + new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of())); var ctrl = new TestSurfaceController(umbracoContextAccessor, helper); var result = ctrl.GetContent(2) as PublishedContentResult; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js index c86b32a101..b106f35efb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umblogin.directive.js @@ -90,7 +90,7 @@ $location.search('invite', null); }), //get the membership provider config for password policies - authResource.getPasswordConfig().then(function (data) { + authResource.getPasswordConfig(0).then(function (data) { vm.invitedUserPasswordModel.passwordPolicies = data; //localize the text diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js index 97eb2bf708..2dd319142b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/users/changepassword.directive.js @@ -15,21 +15,14 @@ var unsubscribe = []; function resetModel(isNew) { - //the model config will contain an object, if it does not we'll create defaults - //NOTE: We will not support doing the password regex on the client side because the regex on the server side - //based on the membership provider cannot always be ported to js from .net directly. + //the model config will contain an object, if it does not we'll create defaults /* { hasPassword: true/false, - requiresQuestionAnswer: true/false, - enableReset: true/false, - enablePasswordRetrieval: true/false, minPasswordLength: 10 } */ - vm.showReset = false; - //set defaults if they are not available if (vm.config.disableToggle === undefined) { vm.config.disableToggle = false; @@ -37,20 +30,6 @@ if (vm.config.hasPassword === undefined) { vm.config.hasPassword = false; } - if (vm.config.enablePasswordRetrieval === undefined) { - vm.config.enablePasswordRetrieval = true; - } - if (vm.config.requiresQuestionAnswer === undefined) { - vm.config.requiresQuestionAnswer = false; - } - //don't enable reset if it is new - that doesn't make sense - if (isNew === "true") { - vm.config.enableReset = false; - } - else if (vm.config.enableReset === undefined) { - vm.config.enableReset = true; - } - if (vm.config.minPasswordLength === undefined) { vm.config.minPasswordLength = 0; } @@ -60,9 +39,7 @@ //if it's not an object then just create a new one vm.passwordValues = { newPassword: null, - oldPassword: null, - reset: null, - answer: null + oldPassword: null }; } else { @@ -73,8 +50,6 @@ vm.passwordValues.newPassword = null; vm.passwordValues.oldPassword = null; } - vm.passwordValues.reset = null; - vm.passwordValues.answer = null; } //the value to compare to match passwords @@ -143,8 +118,7 @@ function showOldPass() { return vm.config.hasPassword && - !vm.config.allowManuallyChangingPassword && - !vm.config.enablePasswordRetrieval && !vm.showReset; + !vm.config.allowManuallyChangingPassword; }; // TODO: I don't think we need this or the cancel button, this can be up to the editor rendering this component diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js index a088b8fc73..cc9da4dbef 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js @@ -204,13 +204,13 @@ function authResource($q, $http, umbRequestHelper, angularHelper) { * @description * Gets the configuration of the user membership provider which is used to configure the change password form */ - getPasswordConfig: function () { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "authenticationApiBaseUrl", - "GetPasswordConfig")), - 'Failed to retrieve membership provider config'); + getPasswordConfig: function (userId) { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "authenticationApiBaseUrl", + "GetPasswordConfig", { userId: userId })), + 'Failed to retrieve membership provider config'); }, /** diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js index d098d3dd7c..5e19235dce 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js @@ -87,6 +87,17 @@ angular.module("umbraco") } } }); + + //go get the config for the membership provider and add it to the model + authResource.getPasswordConfig(user.id).then(function (data) { + $scope.changePasswordModel.config = data; + //ensure the hasPassword config option is set to true (the user of course has a password already assigned) + //this will ensure the oldPassword is shown so they can change it + // disable reset password functionality beacuse it does not make sense inside the backoffice + $scope.changePasswordModel.config.hasPassword = true; + $scope.changePasswordModel.config.disableToggle = true; + }); + } }); } @@ -103,6 +114,12 @@ angular.module("umbraco") }); } + //create the initial model for change password + $scope.changePasswordModel = { + config: {}, + value: {} + }; + updateUserInfo(); //remove all event handlers @@ -113,25 +130,6 @@ angular.module("umbraco") }); - /* ---------- UPDATE PASSWORD ---------- */ - - //create the initial model for change password - $scope.changePasswordModel = { - config: {}, - value: {} - }; - - //go get the config for the membership provider and add it to the model - authResource.getPasswordConfig().then(function(data) { - $scope.changePasswordModel.config = data; - //ensure the hasPassword config option is set to true (the user of course has a password already assigned) - //this will ensure the oldPassword is shown so they can change it - // disable reset password functionality beacuse it does not make sense inside the backoffice - $scope.changePasswordModel.config.hasPassword = true; - $scope.changePasswordModel.config.disableToggle = true; - $scope.changePasswordModel.config.enableReset = false; - }); - $scope.changePassword = function() { if (formHelper.submitForm({ scope: $scope })) { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/users/change-password.html b/src/Umbraco.Web.UI.Client/src/views/components/users/change-password.html index b7b8ec12c7..6ef4378106 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/users/change-password.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/users/change-password.html @@ -1,9 +1,4 @@
-
- Password has been reset to: -
- {{vm.passwordValues.generatedPassword}} -