reverts changes made to UmbracoMembershipProvider and adds another virtual internal method that the UsersMembershipProvider overrides, so now all of the event raising is done in the user specific provider.

This commit is contained in:
Shannon
2017-09-18 19:01:00 +10:00
parent 2a10eed059
commit d468e346f1
2 changed files with 134 additions and 46 deletions

View File

@@ -21,7 +21,7 @@ using Umbraco.Core.Security;
namespace Umbraco.Web.Security.Providers
{
/// <summary>
/// Abstract Membership Provider that users any implementation of IMembershipMemberService{TEntity} service
@@ -32,7 +32,7 @@ namespace Umbraco.Web.Security.Providers
{
protected IMembershipMemberService<TEntity> MemberService { get; private set; }
protected UmbracoMembershipProvider(IMembershipMemberService<TEntity> memberService)
{
MemberService = memberService;
@@ -64,7 +64,7 @@ namespace Umbraco.Web.Security.Providers
/// <exception cref="T:System.ArgumentException">The name of the provider has a length of zero.</exception>
public override void Initialize(string name, NameValueCollection config)
{
if (config == null) {throw new ArgumentNullException("config");}
if (config == null) { throw new ArgumentNullException("config"); }
if (string.IsNullOrEmpty(name)) name = ProviderName;
@@ -92,7 +92,7 @@ namespace Umbraco.Web.Security.Providers
// in order to support updating passwords from the umbraco core, we can't validate the old password
var m = MemberService.GetByUsername(username);
if (m == null) return false;
string salt;
var encodedPassword = EncryptOrHashNewPassword(newPassword, out salt);
@@ -145,7 +145,7 @@ namespace Umbraco.Web.Security.Providers
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the information for the newly created user.
/// </returns>
protected override MembershipUser PerformCreateUser(string memberTypeAlias, string username, string password, string email, string passwordQuestion,
protected override MembershipUser PerformCreateUser(string memberTypeAlias, string username, string password, string email, string passwordQuestion,
string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
// See if the user already exists
@@ -170,11 +170,11 @@ namespace Umbraco.Web.Security.Providers
var member = MemberService.CreateWithIdentity(
username,
email,
FormatPasswordForStorage(encodedPassword, salt),
email,
FormatPasswordForStorage(encodedPassword, salt),
memberTypeAlias,
isApproved);
member.PasswordQuestion = passwordQuestion;
member.RawPasswordAnswerValue = EncryptString(passwordAnswer);
member.LastLoginDate = DateTime.Now;
@@ -218,7 +218,7 @@ namespace Umbraco.Web.Security.Providers
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
var byEmail = MemberService.FindByEmail(emailToMatch, pageIndex, pageSize, out totalRecords, StringPropertyMatchType.Wildcard).ToArray();
var collection = new MembershipUserCollection();
foreach (var m in byEmail)
{
@@ -263,7 +263,7 @@ namespace Umbraco.Web.Security.Providers
var membersList = new MembershipUserCollection();
var pagedMembers = MemberService.GetAll(pageIndex, pageSize, out totalRecords);
foreach (var m in pagedMembers)
{
membersList.Add(ConvertToMembershipUser(m));
@@ -296,7 +296,7 @@ namespace Umbraco.Web.Security.Providers
/// The password for the specified user name.
/// </returns>
protected override string PerformGetPassword(string username, string answer)
{
{
var m = MemberService.GetByUsername(username);
if (m == null)
{
@@ -419,7 +419,7 @@ namespace Umbraco.Web.Security.Providers
// throw new ProviderException("Password answer required for password reset.");
//}
var m = MemberService.GetByUsername(username);
if (m == null)
{
@@ -443,7 +443,7 @@ namespace Umbraco.Web.Security.Providers
m.RawPasswordValue = FormatPasswordForStorage(encodedPassword, salt);
m.LastPasswordChangeDate = DateTime.Now;
MemberService.Save(m);
return generatedPassword;
}
@@ -456,15 +456,21 @@ namespace Umbraco.Web.Security.Providers
/// </returns>
public override bool UnlockUser(string username)
{
var userManager = GetBackofficeUserManager();
return userManager != null && userManager.UnlockUser(username);
}
var member = MemberService.GetByUsername(username);
if (member == null)
{
throw new ProviderException(string.Format("No member with the username '{0}' found", username));
}
internal BackOfficeUserManager<BackOfficeIdentityUser> GetBackofficeUserManager()
{
return HttpContext.Current == null
? null
: HttpContext.Current.GetOwinContext().GetBackOfficeUserManager();
// Non need to update
if (member.IsLockedOut == false) return true;
member.IsLockedOut = false;
member.FailedPasswordAttempts = 0;
MemberService.Save(member);
return true;
}
/// <summary>
@@ -490,7 +496,7 @@ namespace Umbraco.Web.Security.Providers
}
}
m.Email = user.Email;
m.IsApproved = user.IsApproved;
m.IsLockedOut = user.IsLockedOut;
if (user.IsLockedOut)
@@ -502,15 +508,9 @@ namespace Umbraco.Web.Security.Providers
MemberService.Save(m);
}
/// <summary>
/// Verifies that the specified user name and password exist in the data source.
/// </summary>
/// <param name="username">The name of the user to validate.</param>
/// <param name="password">The password for the specified user.</param>
/// <returns>
/// true if the specified username and password are valid; otherwise, false.
/// </returns>
public override bool ValidateUser(string username, string password)
internal virtual ValidateUserResult PerformValidateUser(string username, string password)
{
var member = MemberService.GetByUsername(username);
@@ -522,7 +522,10 @@ namespace Umbraco.Web.Security.Providers
username,
GetCurrentRequestIpAddress()));
return false;
return new ValidateUserResult
{
Authenticated = false
};
}
if (member.IsApproved == false)
@@ -533,7 +536,11 @@ namespace Umbraco.Web.Security.Providers
username,
GetCurrentRequestIpAddress()));
return false;
return new ValidateUserResult
{
Member = member,
Authenticated = false
};
}
if (member.IsLockedOut)
{
@@ -543,11 +550,14 @@ namespace Umbraco.Web.Security.Providers
username,
GetCurrentRequestIpAddress()));
return false;
return new ValidateUserResult
{
Member = member,
Authenticated = false
};
}
var authenticated = CheckPassword(password, member.RawPasswordValue);
var backofficeUserManager = GetBackofficeUserManager();
if (authenticated == false)
{
@@ -566,10 +576,7 @@ namespace Umbraco.Web.Security.Providers
string.Format(
"Login attempt failed for username {0} from IP address {1}, the user is now locked out, max invalid password attempts exceeded",
username,
GetCurrentRequestIpAddress()));
if(backofficeUserManager != null)
backofficeUserManager.RaiseAccountLockedEvent(member.Id);
GetCurrentRequestIpAddress()));
}
else
{
@@ -586,8 +593,6 @@ namespace Umbraco.Web.Security.Providers
{
//we have successfully logged in, reset the AccessFailedCount
member.FailedPasswordAttempts = 0;
if (backofficeUserManager != null)
backofficeUserManager.RaiseResetAccessFailedCountEvent(member.Id);
}
member.LastLoginDate = DateTime.Now;
@@ -596,10 +601,7 @@ namespace Umbraco.Web.Security.Providers
string.Format(
"Login attempt succeeded for username {0} from IP address {1}",
username,
GetCurrentRequestIpAddress()));
if (backofficeUserManager != null)
backofficeUserManager.RaiseLoginSuccessEvent(member.Id);
GetCurrentRequestIpAddress()));
}
//don't raise events for this! It just sets the member dates, if we do raise events this will
@@ -612,7 +614,31 @@ namespace Umbraco.Web.Security.Providers
if (UmbracoVersion.Current >= new Version(7, 3, 0, 0))
MemberService.Save(member, false);
return authenticated;
return new ValidateUserResult
{
Authenticated = authenticated,
Member = member
};
}
/// <summary>
/// Verifies that the specified user name and password exist in the data source.
/// </summary>
/// <param name="username">The name of the user to validate.</param>
/// <param name="password">The password for the specified user.</param>
/// <returns>
/// true if the specified username and password are valid; otherwise, false.
/// </returns>
public override bool ValidateUser(string username, string password)
{
var result = PerformValidateUser(username, password);
return result.Authenticated;
}
internal class ValidateUserResult
{
public TEntity Member { get; set; }
public bool Authenticated { get; set; }
}
}
}

View File

@@ -2,9 +2,11 @@
using System.Configuration.Provider;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Security;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
@@ -80,5 +82,65 @@ namespace Umbraco.Web.Security.Providers
return _defaultMemberTypeAlias;
}
}
/// <summary>
/// Overridden in order to call the BackOfficeUserManager.UnlockUser method in order to raise the user audit events
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
public override bool UnlockUser(string username)
{
var userManager = GetBackofficeUserManager();
//if this is null it means it's not in a web context so we'll revert to calling the base class
if (userManager == null)
return base.UnlockUser(username);
return userManager.UnlockUser(username);
}
/// <summary>
/// Override in order to raise appropriate events via the <see cref="BackOfficeUserManager"/>
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
/// <returns></returns>
internal override ValidateUserResult PerformValidateUser(string username, string password)
{
var result = base.PerformValidateUser(username, password);
var userManager = GetBackofficeUserManager();
if (userManager == null) return result;
if (result.Authenticated == false)
{
var count = result.Member.FailedPasswordAttempts;
if (count >= MaxInvalidPasswordAttempts)
{
userManager.RaiseAccountLockedEvent(result.Member.Id);
}
}
else
{
if (result.Member.FailedPasswordAttempts > 0)
{
//we have successfully logged in, if the failed password attempts was modified it means it was reset
if (result.Member.WasPropertyDirty("FailedPasswordAttempts"))
{
userManager.RaiseResetAccessFailedCountEvent(result.Member.Id);
}
}
}
return result;
}
internal BackOfficeUserManager<BackOfficeIdentityUser> GetBackofficeUserManager()
{
return HttpContext.Current == null
? null
: HttpContext.Current.GetOwinContext().GetBackOfficeUserManager();
}
}
}