From c040cfefcdf413a096d643171fba0b4c0be4cb88 Mon Sep 17 00:00:00 2001 From: Rebecca Date: Thu, 22 Feb 2018 13:02:34 +1000 Subject: [PATCH] Failed Logon Attempts resets to 0 after maximum number of attempts --- .../Security/BackOfficeUserManager.cs | 62 ++++++++++++++----- .../src/views/users/user.controller.js | 2 + .../src/views/users/views/user/details.html | 2 +- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Core/Security/BackOfficeUserManager.cs b/src/Umbraco.Core/Security/BackOfficeUserManager.cs index 4969fa5f2f..38861f300c 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserManager.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserManager.cs @@ -57,7 +57,7 @@ namespace Umbraco.Core.Security [Obsolete("Use the overload specifying all dependencies instead")] public static BackOfficeUserManager Create( IdentityFactoryOptions options, - IUserService userService, + IUserService userService, IExternalLoginService externalLoginService, MembershipProviderBase membershipProvider) { @@ -94,7 +94,7 @@ namespace Umbraco.Core.Security manager.InitUserManager(manager, membershipProvider, contentSectionConfig, options); return manager; } - + [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Use the overload specifying all dependencies instead")] public static BackOfficeUserManager Create( @@ -129,7 +129,7 @@ namespace Umbraco.Core.Security [Obsolete("Use the overload specifying all dependencies instead")] protected void InitUserManager( BackOfficeUserManager manager, - MembershipProviderBase membershipProvider, + MembershipProviderBase membershipProvider, IdentityFactoryOptions options) { InitUserManager(manager, membershipProvider, UmbracoConfig.For.UmbracoSettings().Content, options); @@ -216,8 +216,8 @@ namespace Umbraco.Core.Security /// /// protected void InitUserManager( - BackOfficeUserManager manager, - MembershipProviderBase membershipProvider, + BackOfficeUserManager manager, + MembershipProviderBase membershipProvider, IDataProtectionProvider dataProtectionProvider, IContentSection contentSectionConfig) { @@ -233,7 +233,7 @@ namespace Umbraco.Core.Security //use a custom hasher based on our membership provider manager.PasswordHasher = GetDefaultPasswordHasher(membershipProvider); - + if (dataProtectionProvider != null) { manager.UserTokenProvider = new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")); @@ -373,7 +373,7 @@ namespace Umbraco.Core.Security } #region Overrides for password logic - + /// /// Logic used to validate a username and password /// @@ -469,7 +469,7 @@ namespace Umbraco.Core.Security await UpdateSecurityStampInternal(user); return IdentityResult.Success; - + } /// @@ -507,15 +507,22 @@ namespace Umbraco.Core.Security #endregion - public override Task SetLockoutEndDateAsync(int userId, DateTimeOffset lockoutEnd) + public override async Task SetLockoutEndDateAsync(int userId, DateTimeOffset lockoutEnd) { - var result = base.SetLockoutEndDateAsync(userId, lockoutEnd); + var result = await base.SetLockoutEndDateAsync(userId, lockoutEnd); // The way we unlock is by setting the lockoutEnd date to the current datetime - if (result.Result.Succeeded && lockoutEnd >= DateTimeOffset.UtcNow) + if (result.Succeeded && lockoutEnd >= DateTimeOffset.UtcNow) + { RaiseAccountLockedEvent(userId); + } else + { RaiseAccountUnlockedEvent(userId); + //Resets the login attempt fails back to 0 when unlock is clicked + await ResetAccessFailedCountAsync(userId); + + } return result; } @@ -537,16 +544,39 @@ namespace Umbraco.Core.Security RaiseResetAccessFailedCountEvent(userId); return await UpdateAsync(user); } - - - public override Task AccessFailedAsync(int userId) + + /// + /// Overides the microsoft ASP.NET user managment method + /// + /// + /// + /// returns a Async Task + /// + /// + /// Doesnt set fail attempts back to 0 + /// + public override async Task AccessFailedAsync(int userId) { - var result = base.AccessFailedAsync(userId); + var lockoutStore = (IUserLockoutStore)Store; + var user = await FindByIdAsync(userId); + if (user == null) + throw new InvalidOperationException("No user found by user id " + userId); + + var count = await lockoutStore.IncrementAccessFailedCountAsync(user); + + if (count >= MaxFailedAccessAttemptsBeforeLockout) + { + await lockoutStore.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.Add(DefaultAccountLockoutTimeSpan)); + //NOTE: in normal aspnet identity this would do set the number of failed attempts back to 0 + //here we are persisting the value for the back office + } + + var result = await UpdateAsync(user); //Slightly confusing: this will return a Success if we successfully update the AccessFailed count - if (result.Result.Succeeded) + if (result.Succeeded) RaiseLoginFailedEvent(userId); return result; diff --git a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js index 0f3519c7ba..3a59a50c2c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js @@ -341,8 +341,10 @@ vm.unlockUserButtonState = "busy"; usersResource.unlockUsers([vm.user.id]).then(function (data) { vm.user.userState = 0; + vm.user.failedPasswordAttempts = 0; setUserDisplayState(); vm.unlockUserButtonState = "success"; + formHelper.showNotifications(data); }, function (error) { vm.unlockUserButtonState = "error"; diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html b/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html index 67f204aa2f..83c28f9f99 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/user/details.html @@ -358,4 +358,4 @@ - \ No newline at end of file +