From d0c4b2ab7293f4ccacb6b9bcda237bd51be8a2b6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 1 Jul 2015 18:02:58 +0200 Subject: [PATCH] Fixes user lockout with aspnet identity --- .../Models/Identity/BackOfficeIdentityUser.cs | 24 +++++++++++++++++++ .../Models/Identity/IdentityModelMappings.cs | 5 ++-- .../Security/BackOfficeUserManager.cs | 4 ++++ .../Security/BackOfficeUserStore.cs | 18 +++++++------- .../Security/MembershipProviderBase.cs | 2 +- 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index 9a53023a8d..0d803c26e5 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -38,6 +38,30 @@ namespace Umbraco.Core.Models.Identity public string UserTypeAlias { get; set; } + /// + /// Lockout is always enabled + /// + public override bool LockoutEnabled + { + get { return true; } + set + { + //do nothing + } + } + + /// + /// Based on the user's lockout end date, this will determine if they are locked out + /// + internal bool IsLockedOut + { + get + { + var isLocked = (LockoutEndDateUtc.HasValue && LockoutEndDateUtc.Value.ToLocalTime() >= DateTime.Now); + return isLocked; + } + } + /// /// Overridden to make the retrieval lazy /// diff --git a/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs b/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs index 7e30d4a81e..f57d6683a2 100644 --- a/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs +++ b/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs @@ -14,9 +14,7 @@ namespace Umbraco.Core.Models.Identity config.CreateMap() .ForMember(user => user.Email, expression => expression.MapFrom(user => user.Email)) .ForMember(user => user.Id, expression => expression.MapFrom(user => user.Id)) - .ForMember(user => user.LockoutEnabled, expression => expression.MapFrom(user => user.IsLockedOut)) - //Users currently are locked out for an infinite time, we do not support timed lock outs currently - .ForMember(user => user.LockoutEndDateUtc, expression => expression.UseValue(DateTime.MaxValue.ToUniversalTime())) + .ForMember(user => user.LockoutEndDateUtc, expression => expression.MapFrom(user => user.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?)null)) .ForMember(user => user.UserName, expression => expression.MapFrom(user => user.Username)) .ForMember(user => user.PasswordHash, expression => expression.MapFrom(user => GetPasswordHash(user.RawPasswordValue))) .ForMember(user => user.Culture, expression => expression.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService))) @@ -24,6 +22,7 @@ namespace Umbraco.Core.Models.Identity .ForMember(user => user.StartMediaId, expression => expression.MapFrom(user => user.StartMediaId)) .ForMember(user => user.StartContentId, expression => expression.MapFrom(user => user.StartContentId)) .ForMember(user => user.UserTypeAlias, expression => expression.MapFrom(user => user.UserType.Alias)) + .ForMember(user => user.AccessFailedCount, expression => expression.MapFrom(user => user.FailedPasswordAttempts)) .ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray())); } diff --git a/src/Umbraco.Core/Security/BackOfficeUserManager.cs b/src/Umbraco.Core/Security/BackOfficeUserManager.cs index 798c124880..f86c06c39c 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserManager.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserManager.cs @@ -102,6 +102,10 @@ namespace Umbraco.Core.Security manager.UserLockoutEnabledByDefault = true; manager.MaxFailedAccessAttemptsBeforeLockout = membershipProvider.MaxInvalidPasswordAttempts; + //NOTE: This just needs to be in the future, we currently don't support a lockout timespan, it's either they are locked + // or they are not locked, but this determines what is set on the account lockout date which corresponds to whether they are + // locked out or not. + manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromDays(30); //custom identity factory for creating the identity object for which we auth against in the back office manager.ClaimsIdentityFactory = new BackOfficeClaimsIdentityFactory(); diff --git a/src/Umbraco.Core/Security/BackOfficeUserStore.cs b/src/Umbraco.Core/Security/BackOfficeUserStore.cs index 5745abb02e..e37f9d1a54 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserStore.cs @@ -78,7 +78,7 @@ namespace Umbraco.Core.Security Username = user.UserName, StartContentId = user.StartContentId == 0 ? -1 : user.StartContentId, StartMediaId = user.StartMediaId == 0 ? -1 : user.StartMediaId, - IsLockedOut = user.LockoutEnabled, + IsLockedOut = user.IsLockedOut, IsApproved = true }; @@ -540,8 +540,8 @@ namespace Umbraco.Core.Security if (user == null) throw new ArgumentNullException("user"); return user.LockoutEndDateUtc.HasValue - ? Task.FromResult(new DateTimeOffset(user.LockoutEndDateUtc.Value, TimeSpan.FromHours(0))) - : Task.FromResult(DateTimeOffset.MaxValue); + ? Task.FromResult(DateTimeOffset.MaxValue) + : Task.FromResult(DateTimeOffset.MinValue); } /// @@ -576,7 +576,8 @@ namespace Umbraco.Core.Security public Task ResetAccessFailedCountAsync(BackOfficeIdentityUser user) { if (user == null) throw new ArgumentNullException("user"); - throw new NotImplementedException(); + user.AccessFailedCount = 0; + return Task.FromResult(0); } /// @@ -592,7 +593,7 @@ namespace Umbraco.Core.Security } /// - /// Returns whether the user can be locked out. + /// Returns true /// /// /// @@ -603,7 +604,7 @@ namespace Umbraco.Core.Security } /// - /// Sets whether the user can be locked out. + /// Doesn't actually perform any function, users can always be locked out /// /// /// @@ -635,10 +636,10 @@ namespace Umbraco.Core.Security anythingChanged = true; user.FailedPasswordAttempts = identityUser.AccessFailedCount; } - if (user.IsLockedOut != identityUser.LockoutEnabled) + if (user.IsLockedOut != identityUser.IsLockedOut) { anythingChanged = true; - user.IsLockedOut = identityUser.LockoutEnabled; + user.IsLockedOut = identityUser.IsLockedOut; } if (user.Username != identityUser.UserName && identityUser.UserName.IsNullOrWhiteSpace() == false) { @@ -671,6 +672,7 @@ namespace Umbraco.Core.Security anythingChanged = true; user.SecurityStamp = identityUser.SecurityStamp; } + if (user.AllowedSections.ContainsAll(identityUser.AllowedSections) == false || identityUser.AllowedSections.ContainsAll(user.AllowedSections) == false) { diff --git a/src/Umbraco.Core/Security/MembershipProviderBase.cs b/src/Umbraco.Core/Security/MembershipProviderBase.cs index 794c8fda2d..392c1545d1 100644 --- a/src/Umbraco.Core/Security/MembershipProviderBase.cs +++ b/src/Umbraco.Core/Security/MembershipProviderBase.cs @@ -225,7 +225,7 @@ namespace Umbraco.Core.Security _enablePasswordReset = config.GetValue("enablePasswordReset", false); _requiresQuestionAndAnswer = config.GetValue("requiresQuestionAndAnswer", false); _requiresUniqueEmail = config.GetValue("requiresUniqueEmail", true); - _maxInvalidPasswordAttempts = GetIntValue(config, "maxInvalidPasswordAttempts", 20, false, 0); + _maxInvalidPasswordAttempts = GetIntValue(config, "maxInvalidPasswordAttempts", 5, false, 0); _passwordAttemptWindow = GetIntValue(config, "passwordAttemptWindow", 10, false, 0); _minRequiredPasswordLength = GetIntValue(config, "minRequiredPasswordLength", DefaultMinPasswordLength, true, 0x80); _minRequiredNonAlphanumericCharacters = GetIntValue(config, "minRequiredNonalphanumericCharacters", DefaultMinNonAlphanumericChars, true, 0x80);