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);