More WIP on the membership providers - both new and old. They are now both working with the same up-to-date logic and base classes. Updated the interface definitions on the member services to support the membership provider queries - now to implement the logic.

This commit is contained in:
Shannon
2013-12-20 14:01:10 +11:00
parent 2dd04799b2
commit 414b65b269
11 changed files with 668 additions and 465 deletions

View File

@@ -0,0 +1,14 @@
namespace Umbraco.Core.Persistence.Querying
{
/// <summary>
/// Determine how to match a number or data value
/// </summary>
public enum ValuePropertyMatchType
{
Exact,
GreaterThan,
LessThan,
GreaterThanOrEqualTo,
LessThanOrEqualTo
}
}

View File

@@ -18,40 +18,10 @@ namespace Umbraco.Core.Security
{
//Set the defaults!
DefaultMemberTypeAlias = "Member";
LockPropertyTypeAlias = Constants.Conventions.Member.IsLockedOut;
LastLockedOutPropertyTypeAlias = Constants.Conventions.Member.LastLockoutDate;
FailedPasswordAttemptsPropertyTypeAlias = Constants.Conventions.Member.FailedPasswordAttempts;
ApprovedPropertyTypeAlias = Constants.Conventions.Member.IsApproved;
CommentPropertyTypeAlias = Constants.Conventions.Member.Comments;
LastLoginPropertyTypeAlias = Constants.Conventions.Member.LastLoginDate;
LastPasswordChangedPropertyTypeAlias = Constants.Conventions.Member.LastPasswordChangeDate;
PasswordRetrievalQuestionPropertyTypeAlias = Constants.Conventions.Member.PasswordQuestion;
PasswordRetrievalAnswerPropertyTypeAlias = Constants.Conventions.Member.PasswordAnswer;
}
public string DefaultMemberTypeAlias { get; protected set; }
public string LockPropertyTypeAlias { get; protected set; }
public string LastLockedOutPropertyTypeAlias { get; protected set; }
public string FailedPasswordAttemptsPropertyTypeAlias { get; protected set; }
public string ApprovedPropertyTypeAlias { get; protected set; }
public string CommentPropertyTypeAlias { get; protected set; }
public string LastLoginPropertyTypeAlias { get; protected set; }
public string LastPasswordChangedPropertyTypeAlias { get; protected set; }
public string PasswordRetrievalQuestionPropertyTypeAlias { get; protected set; }
public string PasswordRetrievalAnswerPropertyTypeAlias { get; protected set; }
public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
{
base.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer);
if (string.IsNullOrEmpty(PasswordRetrievalQuestionPropertyTypeAlias) || string.IsNullOrEmpty(PasswordRetrievalAnswerPropertyTypeAlias))
{
throw new NotSupportedException("Updating the password Question and Answer is not valid if the properties aren't set in the config file");
}
return PerformChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer);
}
/// <summary>
/// Adds a new membership user to the data source.
/// </summary>
@@ -398,6 +368,21 @@ namespace Umbraco.Core.Security
throw new NotSupportedException("This provider does not support manually changing the password");
}
var args = new ValidatePasswordEventArgs(username, newPassword, false);
OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
throw args.FailureInformation;
throw new MembershipPasswordException("Change password canceled due to password validation failure.");
}
if (AllowManuallyChangingPassword == false)
{
if (ValidateUser(username, oldPassword) == false) return false;
}
return PerformChangePassword(username, oldPassword, newPassword);
}
@@ -431,10 +416,13 @@ namespace Umbraco.Core.Security
{
throw new NotSupportedException("Updating the password Question and Answer is not available if requiresQuestionAndAnswer is not set in web.config");
}
if (ValidateUser(username, password) == false)
if (AllowManuallyChangingPassword == false)
{
return false;
if (ValidateUser(username, password) == false)
{
return false;
}
}
return PerformChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer);
@@ -534,6 +522,56 @@ namespace Umbraco.Core.Security
/// </returns>
protected abstract MembershipUser PerformCreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
/// <summary>
/// Gets the members password if password retreival is enabled
/// </summary>
/// <param name="username"></param>
/// <param name="answer"></param>
/// <returns></returns>
public sealed override string GetPassword(string username, string answer)
{
if (EnablePasswordRetrieval == false)
throw new ProviderException("Password Retrieval Not Enabled.");
if (PasswordFormat == MembershipPasswordFormat.Hashed)
throw new ProviderException("Cannot retrieve Hashed passwords.");
return PerformGetPassword(username, answer);
}
/// <summary>
/// Gets the members password if password retreival is enabled
/// </summary>
/// <param name="username"></param>
/// <param name="answer"></param>
/// <returns></returns>
protected abstract string PerformGetPassword(string username, string answer);
public sealed override string ResetPassword(string username, string answer)
{
if (EnablePasswordReset == false)
{
throw new NotSupportedException("Password reset is not supported");
}
var newPassword = Membership.GeneratePassword(MinRequiredPasswordLength, MinRequiredNonAlphanumericCharacters);
var args = new ValidatePasswordEventArgs(username, newPassword, true);
OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
{
throw args.FailureInformation;
}
throw new MembershipPasswordException("Reset password canceled due to password validation failure.");
}
return PerformResetPassword(username, answer, newPassword);
}
protected abstract string PerformResetPassword(string username, string answer, string generatedPassword);
protected internal static Attempt<PasswordValidityError> IsPasswordValid(string password, int minRequiredNonAlphanumericChars, string strengthRegex, int minLength)
{
if (minRequiredNonAlphanumericChars > 0)
@@ -561,7 +599,7 @@ namespace Umbraco.Core.Security
return Attempt.Succeed(PasswordValidityError.Ok);
}
/// <summary>
/// Gets the name of the default app.
/// </summary>

View File

@@ -17,18 +17,87 @@ namespace Umbraco.Core.Services
/// <returns></returns>
bool Exists(int id);
/// <summary>
/// Get a member by its id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IMember GetById(int id);
/// <summary>
/// Get a member by the unique key
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
IMember GetByKey(Guid id);
/// <summary>
/// Get all members for the member type alias
/// </summary>
/// <param name="memberTypeAlias"></param>
/// <returns></returns>
IEnumerable<IMember> GetMembersByMemberType(string memberTypeAlias);
/// <summary>
/// Get all members for the member type id
/// </summary>
/// <param name="memberTypeId"></param>
/// <returns></returns>
IEnumerable<IMember> GetMembersByMemberType(int memberTypeId);
/// <summary>
/// Get all members in the member group name specified
/// </summary>
/// <param name="memberGroupName"></param>
/// <returns></returns>
IEnumerable<IMember> GetMembersByGroup(string memberGroupName);
/// <summary>
/// Get all members with the ids specified
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
IEnumerable<IMember> GetAllMembers(params int[] ids);
/// <summary>
/// Delete members of the specified member type id
/// </summary>
/// <param name="memberTypeId"></param>
void DeleteMembersOfType(int memberTypeId);
/// <summary>
/// Get members based on a property search
/// </summary>
/// <param name="propertyTypeAlias"></param>
/// <param name="value"></param>
/// <param name="matchType"></param>
/// <returns></returns>
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, string value, StringPropertyMatchType matchType = StringPropertyMatchType.Exact);
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, int value);
/// <summary>
/// Get members based on a property search
/// </summary>
/// <param name="propertyTypeAlias"></param>
/// <param name="value"></param>
/// <param name="matchType"></param>
/// <returns></returns>
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, int value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact);
/// <summary>
/// Get members based on a property search
/// </summary>
/// <param name="propertyTypeAlias"></param>
/// <param name="value"></param>
/// <returns></returns>
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, bool value);
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, DateTime value);
/// <summary>
/// Get members based on a property search
/// </summary>
/// <param name="propertyTypeAlias"></param>
/// <param name="value"></param>
/// <param name="matchType"></param>
/// <returns></returns>
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, DateTime value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact);
}
}

View File

@@ -31,6 +31,11 @@ namespace Umbraco.Core.Services
IMember GetById(object id);
/// <summary>
/// Get a member by email
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
IMember GetByEmail(string email);
IMember GetByUsername(string login);
@@ -44,5 +49,20 @@ namespace Umbraco.Core.Services
IEnumerable<IMember> FindMembersByEmail(string emailStringToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
IEnumerable<IMember> FindMembersByUsername(string login, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
/// <summary>
/// Gets the total number of members based on the count type
/// </summary>
/// <returns></returns>
int GetMemberCount(MemberCountType countType);
/// <summary>
/// Gets a list of paged member data
/// </summary>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <param name="totalRecords"></param>
/// <returns></returns>
IEnumerable<IMember> GetAllMembers(int pageIndex, int pageSize, out int totalRecords);
}
}

View File

@@ -0,0 +1,13 @@
namespace Umbraco.Core.Services
{
/// <summary>
/// The types of members to count
/// </summary>
public enum MemberCountType
{
All,
Online,
LockedOut,
Approved
}
}

View File

@@ -310,8 +310,9 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="propertyTypeAlias"></param>
/// <param name="value"></param>
/// <param name="matchType"></param>
/// <returns></returns>
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, int value)
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, int value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact)
{
using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
{
@@ -352,8 +353,9 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="propertyTypeAlias"></param>
/// <param name="value"></param>
/// <param name="matchType"></param>
/// <returns></returns>
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, DateTime value)
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, DateTime value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact)
{
using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
{
@@ -372,6 +374,26 @@ namespace Umbraco.Core.Services
#region IMembershipMemberService Implementation
/// <summary>
/// Returns the count of members based on the countType
/// </summary>
/// <param name="countType"></param>
/// <returns></returns>
/// <remarks>
/// The way the Online count is done is the same way that it is done in the MS SqlMembershipProvider - We query for any members
/// that have their last active date within the Membership.UserIsOnlineTimeWindow (which is in minutes). It isn't exact science
/// but that is how MS have made theirs so we'll follow that principal.
/// </remarks>
public int GetMemberCount(MemberCountType countType)
{
throw new NotImplementedException();
}
public IEnumerable<IMember> GetAllMembers(int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
/// <summary>
/// Creates and persists a new Member
/// </summary>

View File

@@ -203,6 +203,7 @@
<Compile Include="Persistence\Querying\SqlStringExtensions.cs" />
<Compile Include="Persistence\Querying\StringPropertyMatchType.cs" />
<Compile Include="Persistence\Querying\TextColumnType.cs" />
<Compile Include="Persistence\Querying\ValuePropertyMatchType.cs" />
<Compile Include="Persistence\SqlSyntax\MySqlSyntax.cs" />
<Compile Include="Persistence\SqlSyntax\SqlCeSyntax.cs" />
<Compile Include="Persistence\SqlSyntax\SqlServerSyntax.cs" />
@@ -772,6 +773,7 @@
<Compile Include="Services\IUserService.cs" />
<Compile Include="Services\LocalizationService.cs" />
<Compile Include="Services\MediaService.cs" />
<Compile Include="Services\MemberCountType.cs" />
<Compile Include="Services\MemberService.cs" />
<Compile Include="Services\MemberTypeService.cs" />
<Compile Include="Services\RelationService.cs" />

View File

@@ -13,6 +13,16 @@ using Umbraco.Web.Security.Providers;
namespace Umbraco.Tests.Membership
{
[TestFixture]
public class MembersMembershipProviderTests
{
//[Test]
//public void Set_Default_Member_Type_On_Init()
//[Test]
//public void Question_Answer_Is_Encrypted()
}
[TestFixture]
public class MembershipProviderBaseTests
{
@@ -111,16 +121,6 @@ namespace Umbraco.Tests.Membership
private class TestProvider : MembershipProviderBase
{
public override string GetPassword(string username, string answer)
{
throw new NotImplementedException();
}
public override string ResetPassword(string username, string answer)
{
throw new NotImplementedException();
}
public override void UpdateUser(MembershipUser user)
{
throw new NotImplementedException();
@@ -190,6 +190,16 @@ namespace Umbraco.Tests.Membership
{
throw new NotImplementedException();
}
protected override string PerformGetPassword(string username, string answer)
{
throw new NotImplementedException();
}
protected override string PerformResetPassword(string username, string answer, string generatedPassword)
{
throw new NotImplementedException();
}
}
}

View File

@@ -61,48 +61,7 @@ namespace Umbraco.Web.Security.Providers
// _defaultMemberTypeAlias = MemberType.GetAll[0].Alias;
//else
// throw new ProviderException("No default MemberType alias is specified in the web.config string. Please add a 'defaultMemberTypeAlias' to the add element in the provider declaration in web.config");
// test for approve status
if (config["umbracoApprovePropertyTypeAlias"] != null)
{
ApprovedPropertyTypeAlias = config["umbracoApprovePropertyTypeAlias"];
}
// test for lock attempts
if (config["umbracoLockPropertyTypeAlias"] != null)
{
LockPropertyTypeAlias = config["umbracoLockPropertyTypeAlias"];
}
if (config["umbracoLastLockedPropertyTypeAlias"] != null)
{
LastLockedOutPropertyTypeAlias = config["umbracoLastLockedPropertyTypeAlias"];
}
if (config["umbracoLastPasswordChangedPropertyTypeAlias"] != null)
{
LastPasswordChangedPropertyTypeAlias = config["umbracoLastPasswordChangedPropertyTypeAlias"];
}
if (config["umbracoFailedPasswordAttemptsPropertyTypeAlias"] != null)
{
FailedPasswordAttemptsPropertyTypeAlias = config["umbracoFailedPasswordAttemptsPropertyTypeAlias"];
}
// comment property
if (config["umbracoCommentPropertyTypeAlias"] != null)
{
CommentPropertyTypeAlias = config["umbracoCommentPropertyTypeAlias"];
}
// last login date
if (config["umbracoLastLoginPropertyTypeAlias"] != null)
{
LastLoginPropertyTypeAlias = config["umbracoLastLoginPropertyTypeAlias"];
}
// password retrieval
if (config["umbracoPasswordRetrievalQuestionPropertyTypeAlias"] != null)
{
PasswordRetrievalQuestionPropertyTypeAlias = config["umbracoPasswordRetrievalQuestionPropertyTypeAlias"];
}
if (config["umbracoPasswordRetrievalAnswerPropertyTypeAlias"] != null)
{
PasswordRetrievalAnswerPropertyTypeAlias = config["umbracoPasswordRetrievalAnswerPropertyTypeAlias"];
}
}
/// <summary>
@@ -123,17 +82,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;
var args = new ValidatePasswordEventArgs(username, newPassword, false);
OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
throw args.FailureInformation;
throw new MembershipPasswordException("Change password canceled due to password validation failure.");
}
string salt;
var encodedPassword = EncryptOrHashNewPassword(newPassword, out salt);
@@ -289,7 +238,45 @@ namespace Umbraco.Web.Security.Providers
}
return collection;
}
/// <summary>
/// Gets a collection of all the users in the data source in pages of data.
/// </summary>
/// <param name="pageIndex">The index of the page of results to return. pageIndex is zero-based.</param>
/// <param name="pageSize">The size of the page of results to return.</param>
/// <param name="totalRecords">The total number of matched users.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUserCollection"></see> collection that contains a page of pageSize<see cref="T:System.Web.Security.MembershipUser"></see> objects beginning at the page specified by pageIndex.
/// </returns>
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
var membersList = new MembershipUserCollection();
var pagedMembers = MemberService.GetAllMembers(pageIndex, pageSize, out totalRecords);
foreach (var m in pagedMembers)
{
membersList.Add(m.AsConcreteMembershipUser());
}
return membersList;
}
/// <summary>
/// Gets the number of users currently accessing the application.
/// </summary>
/// <returns>
/// The number of users currently accessing the application.
/// </returns>
/// <remarks>
/// The way this is done is the same way that it is done in the MS SqlMembershipProvider - We query for any members
/// that have their last active date within the Membership.UserIsOnlineTimeWindow (which is in minutes). It isn't exact science
/// but that is how MS have made theirs so we'll follow that principal.
/// </remarks>
public override int GetNumberOfUsersOnline()
{
return MemberService.GetMemberCount(MemberCountType.Online);
}
/// <summary>
/// Gets the password for the specified user name from the data source.
/// </summary>
@@ -298,168 +285,24 @@ namespace Umbraco.Web.Security.Providers
/// <returns>
/// The password for the specified user name.
/// </returns>
public override string GetPassword(string username, string answer)
{
if (EnablePasswordRetrieval == false)
throw new ProviderException("Password Retrieval Not Enabled.");
if (PasswordFormat == MembershipPasswordFormat.Hashed)
throw new ProviderException("Cannot retrieve Hashed passwords.");
var member = MemberService.GetByUsername(username);
if (RequiresQuestionAndAnswer && member.PasswordAnswer != answer)
protected override string PerformGetPassword(string username, string answer)
{
var m = MemberService.GetByUsername(username);
if (m == null)
{
throw new ProviderException("Password retrieval answer doesn't match");
}
return member.Password;
}
/// <summary>
/// Resets a user's password to a new, automatically generated password.
/// </summary>
/// <param name="username">The user to reset the password for.</param>
/// <param name="answer">The password answer for the specified user (not used with Umbraco).</param>
/// <returns>The new password for the specified user.</returns>
public override string ResetPassword(string username, string answer)
{
//TODO: Get logic from other provider
throw new NotImplementedException();
//if (EnablePasswordReset == false)
// throw new ProviderException("Password reset is Not Enabled.");
//var member = MemberService.GetByUsername(username);
//if (member == null)
// throw new ProviderException("The supplied user is not found");
//if(member.IsLockedOut)
// throw new ProviderException("The member is locked out.");
//if (RequiresQuestionAndAnswer == false || (RequiresQuestionAndAnswer && answer == member.PasswordAnswer))
//{
// member.Password =
// EncryptOrHashPassword(Membership.GeneratePassword(MinRequiredPasswordLength,
// MinRequiredNonAlphanumericCharacters));
// MemberService.Save(member);
//}
//else
//{
// throw new MembershipPasswordException("Incorrect password answer");
//}
//return null;
}
/// <summary>
/// Updates e-mail and potentially approved status, lock status and comment on a user.
/// Note: To automatically support lock, approve and comments you'll need to add references to the membertype properties in the
/// 'Member' element in web.config by adding their aliases to the 'umbracoApprovePropertyTypeAlias', 'umbracoLockPropertyTypeAlias' and 'umbracoCommentPropertyTypeAlias' attributes
/// </summary>
/// <param name="user">A <see cref="T:System.Web.Security.MembershipUser"></see> object that represents the user to update and the updated information for the user.</param>
public override void UpdateUser(MembershipUser user)
{
//var member = user.AsIMember();
//MemberService.Save(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 member = MemberService.GetByUsername(username);
if (member == null || member.IsApproved == false) return false;
if (member.IsLockedOut)
throw new ProviderException("The member is locked out.");
string salt;
var encodedPassword = EncryptOrHashNewPassword(password, out salt);
var authenticated = (encodedPassword == member.Password);
if (authenticated == false)
{
// TODO: Increment login attempts - lock if too many.
//var count = member.GetValue<int>("loginAttempts");
//count++;
//if (count >= _maxInvalidPasswordAttempts)
//{
// member.SetValue("loginAttempts", 0);
// member.IsLockedOut = true;
// throw new ProviderException("The member " + member.Username + " is locked out.");
//}
//else
//{
// member.SetValue("loginAttempts", count);
//}
}
else
{
// add this later - member.SetValue("loginAttempts", 0);
member.LastLoginDate = DateTime.Now;
throw new ProviderException("The supplied user is not found");
}
MemberService.Save(member);
return authenticated;
}
//TODO: We need to encrypt the answer here to match against the encrypted answer in the database
/// <summary>
/// Clears a lock so that the membership user can be validated.
/// </summary>
/// <param name="username">The membership user to clear the lock status for.</param>
/// <returns>
/// true if the membership user was successfully unlocked; otherwise, false.
/// </returns>
public override bool UnlockUser(string username)
{
var member = MemberService.GetByUsername(username);
if(member == null)
throw new ProviderException("Cannot find member " + username);
// Non need to update
if (member.IsLockedOut == false) return true;
member.IsLockedOut = false;
// TODO: add this later - member.SetValue("loginAttempts", 0);
MemberService.Save(member);
return true;
}
/// <summary>
/// Gets information from the data source for a user based on the unique identifier for the membership user. Provides an option to update the last-activity date/time stamp for the user.
/// </summary>
/// <param name="providerUserKey">The unique identifier for the membership user to get information for.</param>
/// <param name="userIsOnline">true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the specified user's information from the data source.
/// </returns>
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
var member = MemberService.GetById(providerUserKey);
if (userIsOnline)
if (RequiresQuestionAndAnswer && m.PasswordAnswer != answer)
{
member.UpdateDate = DateTime.Now;
MemberService.Save(member);
throw new ProviderException("Incorrect password answer");
}
return member.AsConcreteMembershipUser();
var decodedPassword = DecodePassword(m.Password);
return decodedPassword;
}
/// <summary>
@@ -473,9 +316,40 @@ namespace Umbraco.Web.Security.Providers
public override MembershipUser GetUser(string username, bool userIsOnline)
{
var member = MemberService.GetByUsername(username);
if (member == null)
{
return null;
}
if (userIsOnline)
{
member.LastLoginDate = DateTime.Now;
member.UpdateDate = DateTime.Now;
MemberService.Save(member);
}
return member.AsConcreteMembershipUser();
}
/// <summary>
/// Gets information from the data source for a user based on the unique identifier for the membership user. Provides an option to update the last-activity date/time stamp for the user.
/// </summary>
/// <param name="providerUserKey">The unique identifier for the membership user to get information for.</param>
/// <param name="userIsOnline">true to update the last-activity date/time stamp for the user; false to return user information without updating the last-activity date/time stamp for the user.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the specified user's information from the data source.
/// </returns>
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
var member = MemberService.GetById(providerUserKey);
if (member == null)
{
return null;
}
if (userIsOnline)
{
member.LastLoginDate = DateTime.Now;
member.UpdateDate = DateTime.Now;
MemberService.Save(member);
}
@@ -497,33 +371,158 @@ namespace Umbraco.Web.Security.Providers
return member == null ? null : member.Username;
}
/// <summary>
/// Gets a collection of all the users in the data source in pages of data.
/// Resets a user's password to a new, automatically generated password.
/// </summary>
/// <param name="pageIndex">The index of the page of results to return. pageIndex is zero-based.</param>
/// <param name="pageSize">The size of the page of results to return.</param>
/// <param name="totalRecords">The total number of matched users.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUserCollection"></see> collection that contains a page of pageSize<see cref="T:System.Web.Security.MembershipUser"></see> objects beginning at the page specified by pageIndex.
/// </returns>
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
/// <param name="username">The user to reset the password for.</param>
/// <param name="answer">The password answer for the specified user (not used with Umbraco).</param>
/// <param name="generatedPassword"></param>
/// <returns>The new password for the specified user.</returns>
protected override string PerformResetPassword(string username, string answer, string generatedPassword)
{
throw new System.NotImplementedException();
//TODO: This should be here - but how do we update failure count in this provider??
//if (answer == null && RequiresQuestionAndAnswer)
//{
// UpdateFailureCount(username, "passwordAnswer");
// throw new ProviderException("Password answer required for password reset.");
//}
var m = MemberService.GetByUsername(username);
if (m == null)
{
throw new ProviderException("The supplied user is not found");
}
if (m.IsLockedOut)
{
throw new ProviderException("The member is locked out.");
}
//TODO: We need to encrypt the answer here to match against the encrypted answer in the database
if (RequiresQuestionAndAnswer && m.PasswordAnswer != answer)
{
throw new ProviderException("Incorrect password answer");
}
string salt;
var encodedPassword = EncryptOrHashNewPassword(generatedPassword, out salt);
m.Password = encodedPassword;
m.LastPasswordChangeDate = DateTime.Now;
MemberService.Save(m);
return generatedPassword;
}
/// <summary>
/// Gets the number of users currently accessing the application.
/// Clears a lock so that the membership user can be validated.
/// </summary>
/// <param name="username">The membership user to clear the lock status for.</param>
/// <returns>
/// The number of users currently accessing the application.
/// true if the membership user was successfully unlocked; otherwise, false.
/// </returns>
public override int GetNumberOfUsersOnline()
public override bool UnlockUser(string username)
{
throw new System.NotImplementedException();
var member = MemberService.GetByUsername(username);
if (member == null)
{
throw new ProviderException(string.Format("No member with the username '{0}' found", username));
}
// Non need to update
if (member.IsLockedOut == false) return true;
member.IsLockedOut = false;
member.FailedPasswordAttempts = 0;
MemberService.Save(member);
return true;
}
/// <summary>
/// Updates e-mail approved status, lock status and comment on a user.
/// </summary>
/// <param name="user">A <see cref="T:System.Web.Security.MembershipUser"></see> object that represents the user to update and the updated information for the user.</param>
public override void UpdateUser(MembershipUser user)
{
var m = MemberService.GetByUsername(user.UserName);
if (m == null)
{
throw new ProviderException(string.Format("No member with the username '{0}' found", user.UserName));
}
m.Email = user.Email;
m.IsApproved = user.IsApproved;
m.IsLockedOut = user.IsLockedOut;
if (user.IsLockedOut)
{
m.LastLockoutDate = DateTime.Now;
}
m.Comments = user.Comment;
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)
{
var member = MemberService.GetByUsername(username);
if (member == null) return false;
if (member.IsApproved == false)
{
LogHelper.Info<MembersMembershipProvider>("Cannot validate member " + username + " because they are not approved");
return false;
}
if (member.IsLockedOut)
{
LogHelper.Info<MembersMembershipProvider>("Cannot validate member " + username + " because they are currently locked out");
return false;
}
string salt;
var encodedPassword = EncryptOrHashNewPassword(password, out salt);
var authenticated = (encodedPassword == member.Password);
if (authenticated == false)
{
// TODO: Increment login attempts - lock if too many.
var count = member.FailedPasswordAttempts;
count++;
member.FailedPasswordAttempts = count;
if (count >= MaxInvalidPasswordAttempts)
{
member.IsLockedOut = true;
member.LastLockoutDate = DateTime.Now;
LogHelper.Info<MembersMembershipProvider>("Member " + username + " is now locked out, max invalid password attempts exceeded");
}
}
else
{
member.FailedPasswordAttempts = 0;
member.LastLoginDate = DateTime.Now;
}
MemberService.Save(member);
return authenticated;
}
public override string ToString()
{

View File

@@ -305,7 +305,7 @@ namespace umbraco.providers
/// <returns>
/// The password for the specified user name.
/// </returns>
public override string GetPassword(string username, string answer)
protected override string PerformGetPassword(string username, string answer)
{
throw new ProviderException("Password Retrieval Not Enabled.");
}
@@ -355,13 +355,8 @@ namespace umbraco.providers
/// <param name="username">The user to reset the password for.</param>
/// <param name="answer">The password answer for the specified user.</param>
/// <returns>The new password for the specified user.</returns>
public override string ResetPassword(string username, string answer)
{
if (EnablePasswordReset == false)
{
throw new NotSupportedException("Password reset is not supported");
}
protected override string PerformResetPassword(string username, string answer, string generatedPassword)
{
//TODO: This should be here - but how do we update failure count in this provider??
//if (answer == null && RequiresQuestionAndAnswer)
//{
@@ -370,18 +365,7 @@ namespace umbraco.providers
// throw new ProviderException("Password answer required for password reset.");
//}
var newPassword = Membership.GeneratePassword(MinRequiredPasswordLength, MinRequiredNonAlphanumericCharacters);
var args = new ValidatePasswordEventArgs(username, newPassword, true);
OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
throw args.FailureInformation;
throw new MembershipPasswordException("Reset password canceled due to password validation failure.");
}
var found = User.GetAllByLoginName(username, false);
var found = User.GetAllByLoginName(username, false).ToArray();
if (found == null || found.Any() == false)
throw new MembershipPasswordException("The supplied user is not found");
@@ -389,12 +373,12 @@ namespace umbraco.providers
//Yes, it's true, this actually makes a db call to set the password
string salt;
var encPass = EncryptOrHashNewPassword(newPassword, out salt);
var encPass = EncryptOrHashNewPassword(generatedPassword, out salt);
user.Password = FormatPasswordForStorage(encPass, salt);
//call this just for fun.
user.Save();
return newPassword;
return generatedPassword;
}
/// <summary>

View File

@@ -31,12 +31,35 @@ namespace umbraco.providers.members
public class UmbracoMembershipProvider : UmbracoMembershipProviderBase
{
public UmbracoMembershipProvider()
{
LockPropertyTypeAlias = Constants.Conventions.Member.IsLockedOut;
LastLockedOutPropertyTypeAlias = Constants.Conventions.Member.LastLockoutDate;
FailedPasswordAttemptsPropertyTypeAlias = Constants.Conventions.Member.FailedPasswordAttempts;
ApprovedPropertyTypeAlias = Constants.Conventions.Member.IsApproved;
CommentPropertyTypeAlias = Constants.Conventions.Member.Comments;
LastLoginPropertyTypeAlias = Constants.Conventions.Member.LastLoginDate;
LastPasswordChangedPropertyTypeAlias = Constants.Conventions.Member.LastPasswordChangeDate;
PasswordRetrievalQuestionPropertyTypeAlias = Constants.Conventions.Member.PasswordQuestion;
PasswordRetrievalAnswerPropertyTypeAlias = Constants.Conventions.Member.PasswordAnswer;
}
#region Fields
private string _providerName = Member.UmbracoMemberProviderName;
#endregion
public string LockPropertyTypeAlias { get; protected set; }
public string LastLockedOutPropertyTypeAlias { get; protected set; }
public string FailedPasswordAttemptsPropertyTypeAlias { get; protected set; }
public string ApprovedPropertyTypeAlias { get; protected set; }
public string CommentPropertyTypeAlias { get; protected set; }
public string LastLoginPropertyTypeAlias { get; protected set; }
public string LastPasswordChangedPropertyTypeAlias { get; protected set; }
public string PasswordRetrievalQuestionPropertyTypeAlias { get; protected set; }
public string PasswordRetrievalAnswerPropertyTypeAlias { get; protected set; }
/// <summary>
/// Override to maintain backwards compatibility with 0 required non-alphanumeric chars
/// </summary>
@@ -164,17 +187,7 @@ namespace umbraco.providers.members
// in order to support updating passwords from the umbraco core, we can't validate the old password
var m = Member.GetMemberFromLoginName(username);
if (m == null) return false;
var args = new ValidatePasswordEventArgs(username, newPassword, false);
OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
throw args.FailureInformation;
throw new MembershipPasswordException("Change password canceled due to password validation failure.");
}
string salt;
var encodedPassword = EncryptOrHashNewPassword(newPassword, out salt);
m.ChangePassword(
@@ -199,6 +212,11 @@ namespace umbraco.providers.members
/// </returns>
protected override bool PerformChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
{
if (string.IsNullOrEmpty(PasswordRetrievalQuestionPropertyTypeAlias) || string.IsNullOrEmpty(PasswordRetrievalAnswerPropertyTypeAlias))
{
throw new NotSupportedException("Updating the password Question and Answer is not valid if the properties aren't set in the config file");
}
var m = Member.GetMemberFromLoginName(username);
if (m == null)
{
@@ -409,50 +427,45 @@ namespace umbraco.providers.members
/// <returns>
/// The password for the specified user name.
/// </returns>
public override string GetPassword(string username, string answer)
protected override string PerformGetPassword(string username, string answer)
{
if (EnablePasswordRetrieval == false)
throw new ProviderException("Password Retrieval Not Enabled.");
if (PasswordFormat == MembershipPasswordFormat.Hashed)
throw new ProviderException("Cannot retrieve Hashed passwords.");
var m = Member.GetMemberFromLoginName(username);
if (m != null)
{
if (RequiresQuestionAndAnswer)
{
// check if password answer property alias is set
if (string.IsNullOrEmpty(PasswordRetrievalAnswerPropertyTypeAlias) == false)
{
// check if user is locked out
if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false)
{
var isLockedOut = false;
bool.TryParse(GetMemberProperty(m, LockPropertyTypeAlias, true), out isLockedOut);
if (isLockedOut)
{
throw new MembershipPasswordException("The supplied user is locked out");
}
}
// match password answer
if (GetMemberProperty(m, PasswordRetrievalAnswerPropertyTypeAlias, false) != answer)
{
throw new MembershipPasswordException("Incorrect password answer");
}
}
else
{
throw new ProviderException("Password retrieval answer property alias is not set! To automatically support password question/answers you'll need to add references to the membertype properties in the 'Member' element in web.config by adding their aliases to the 'umbracoPasswordRetrievalQuestionPropertyTypeAlias' and 'umbracoPasswordRetrievalAnswerPropertyTypeAlias' attributes");
}
}
}
if (m == null)
{
throw new MembershipPasswordException("The supplied user is not found");
}
return m.GetPassword();
// check if user is locked out
if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false)
{
var isLockedOut = false;
bool.TryParse(GetMemberProperty(m, LockPropertyTypeAlias, true), out isLockedOut);
if (isLockedOut)
{
throw new MembershipPasswordException("The supplied user is locked out");
}
}
if (RequiresQuestionAndAnswer)
{
// check if password answer property alias is set
if (string.IsNullOrEmpty(PasswordRetrievalAnswerPropertyTypeAlias) == false)
{
// match password answer
if (GetMemberProperty(m, PasswordRetrievalAnswerPropertyTypeAlias, false) != answer)
{
throw new MembershipPasswordException("Incorrect password answer");
}
}
else
{
throw new ProviderException("Password retrieval answer property alias is not set! To automatically support password question/answers you'll need to add references to the membertype properties in the 'Member' element in web.config by adding their aliases to the 'umbracoPasswordRetrievalQuestionPropertyTypeAlias' and 'umbracoPasswordRetrievalAnswerPropertyTypeAlias' attributes");
}
}
var decodedPassword = DecodePassword(m.GetPassword());
return decodedPassword;
}
/// <summary>
@@ -465,11 +478,21 @@ namespace umbraco.providers.members
/// </returns>
public override MembershipUser GetUser(string username, bool userIsOnline)
{
if (String.IsNullOrEmpty(username))
if (string.IsNullOrEmpty(username))
return null;
Member m = Member.GetMemberFromLoginName(username);
if (m == null) return null;
else return ConvertToMembershipUser(m);
var m = Member.GetMemberFromLoginName(username);
if (m == null)
{
return null;
}
if (userIsOnline && LastLoginPropertyTypeAlias.IsNullOrWhiteSpace() == false)
{
UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now);
}
return ConvertToMembershipUser(m);
}
/// <summary>
@@ -486,14 +509,23 @@ namespace umbraco.providers.members
if (asGuid.Success)
{
var m = new Member(asGuid.Result);
if (userIsOnline && LastLoginPropertyTypeAlias.IsNullOrWhiteSpace() == false)
{
UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now);
}
return ConvertToMembershipUser(m);
}
var asInt = providerUserKey.TryConvertTo<int>();
if (asInt.Success)
{
var m = new Member(asInt.Result);
if (userIsOnline && LastLoginPropertyTypeAlias.IsNullOrWhiteSpace() == false)
{
UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now);
}
return ConvertToMembershipUser(m);
}
throw new InvalidOperationException("The " + GetType() + " provider only supports GUID or Int as a providerUserKey");
}
@@ -508,7 +540,7 @@ namespace umbraco.providers.members
/// </returns>
public override string GetUserNameByEmail(string email)
{
Member m = Member.GetMemberFromEmail(email);
var m = Member.GetMemberFromEmail(email);
return m == null ? null : m.LoginName;
}
@@ -517,14 +549,10 @@ namespace umbraco.providers.members
/// </summary>
/// <param name="username">The user to reset the password for.</param>
/// <param name="answer">The password answer for the specified user (not used with Umbraco).</param>
/// <param name="generatedPassword"></param>
/// <returns>The new password for the specified user.</returns>
public override string ResetPassword(string username, string answer)
protected override string PerformResetPassword(string username, string answer, string generatedPassword)
{
if (EnablePasswordReset == false)
{
throw new NotSupportedException("Password reset is not supported");
}
//TODO: This should be here - but how do we update failure count in this provider??
//if (answer == null && RequiresQuestionAndAnswer)
//{
@@ -532,42 +560,33 @@ namespace umbraco.providers.members
// throw new ProviderException("Password answer required for password reset.");
//}
var newPassword = Membership.GeneratePassword(MinRequiredPasswordLength, MinRequiredNonAlphanumericCharacters);
var args = new ValidatePasswordEventArgs(username, newPassword, true);
OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
throw args.FailureInformation;
throw new MembershipPasswordException("Reset password canceled due to password validation failure.");
}
var m = Member.GetMemberFromLoginName(username);
if (m == null)
throw new MembershipPasswordException("The supplied user is not found");
{
throw new ProviderException("The supplied user is not found");
}
// check if user is locked out
if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false)
{
var isLockedOut = false;
bool.TryParse(GetMemberProperty(m, LockPropertyTypeAlias, true), out isLockedOut);
if (isLockedOut)
{
throw new ProviderException("The member is locked out.");
}
}
if (RequiresQuestionAndAnswer)
{
// check if password answer property alias is set
if (string.IsNullOrEmpty(PasswordRetrievalAnswerPropertyTypeAlias) == false)
{
// check if user is locked out
if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false)
{
var isLockedOut = false;
bool.TryParse(GetMemberProperty(m, LockPropertyTypeAlias, true), out isLockedOut);
if (isLockedOut)
{
throw new MembershipPasswordException("The supplied user is locked out");
}
}
// match password answer
if (GetMemberProperty(m, PasswordRetrievalAnswerPropertyTypeAlias, false) != answer)
{
throw new MembershipPasswordException("Incorrect password answer");
throw new ProviderException("Incorrect password answer");
}
}
else
@@ -577,10 +596,9 @@ namespace umbraco.providers.members
}
string salt;
var encodedPassword = EncryptOrHashNewPassword(newPassword, out salt);
var encodedPassword = EncryptOrHashNewPassword(generatedPassword, out salt);
//set the password on the member
m.ChangePassword(
FormatPasswordForStorage(encodedPassword, salt));
m.ChangePassword(FormatPasswordForStorage(encodedPassword, salt));
if (string.IsNullOrEmpty(LastPasswordChangedPropertyTypeAlias) == false)
{
@@ -589,7 +607,7 @@ namespace umbraco.providers.members
m.Save();
return newPassword;
return generatedPassword;
}
/// <summary>
@@ -607,10 +625,14 @@ namespace umbraco.providers.members
if (m != null)
{
UpdateMemberProperty(m, LockPropertyTypeAlias, 0);
if (string.IsNullOrEmpty(FailedPasswordAttemptsPropertyTypeAlias) == false)
{
UpdateMemberProperty(m, FailedPasswordAttemptsPropertyTypeAlias, 0);
}
m.Save();
return true;
}
throw new Exception(String.Format("No member with the username '{0}' found", userName));
throw new ProviderException(string.Format("No member with the username '{0}' found", userName));
}
throw new ProviderException("To enable lock/unlocking, you need to add a 'bool' property on your membertype and add the alias of the property in the 'umbracoLockPropertyTypeAlias' attribute of the membership element in the web.config.");
}
@@ -622,6 +644,12 @@ namespace umbraco.providers.members
public override void UpdateUser(MembershipUser user)
{
var m = Member.GetMemberFromLoginName(user.UserName);
if (m == null)
{
throw new ProviderException(string.Format("No member with the username '{0}' found", user.UserName));
}
m.Email = user.Email;
// if supported, update approve status
@@ -640,6 +668,86 @@ namespace umbraco.providers.members
m.Save();
}
/// <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 m = Member.GetMemberFromLoginAndEncodedPassword(username, EncryptOrHashExistingPassword(password));
if (m != null)
{
// check for lock status. If locked, then set the member property to null
if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false)
{
string lockedStatus = GetMemberProperty(m, LockPropertyTypeAlias, true);
if (string.IsNullOrEmpty(lockedStatus) == false)
{
var isLocked = false;
if (bool.TryParse(lockedStatus, out isLocked))
{
if (isLocked)
{
LogHelper.Info<UmbracoMembershipProvider>("Cannot validate member " + username + " because they are currently locked out");
m = null;
}
}
}
}
//check for approve status. If not approved, then set the member property to null
if (m != null && CheckApproveStatus(m) == false)
{
LogHelper.Info<UmbracoMembershipProvider>("Cannot validate member " + username + " because they are not approved");
m = null;
}
// maybe update login date
if (m != null && string.IsNullOrEmpty(LastLoginPropertyTypeAlias) == false)
{
UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now);
}
// maybe reset password attempts
if (m != null && string.IsNullOrEmpty(FailedPasswordAttemptsPropertyTypeAlias) == false)
{
UpdateMemberProperty(m, FailedPasswordAttemptsPropertyTypeAlias, 0);
}
// persist data
if (m != null)
m.Save();
}
else if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false
&& string.IsNullOrEmpty(FailedPasswordAttemptsPropertyTypeAlias) == false)
{
var updateMemberDataObject = Member.GetMemberFromLoginName(username);
// update fail rate if it's approved
if (updateMemberDataObject != null && CheckApproveStatus(updateMemberDataObject))
{
int failedAttempts = 0;
int.TryParse(GetMemberProperty(updateMemberDataObject, FailedPasswordAttemptsPropertyTypeAlias, false), out failedAttempts);
failedAttempts = failedAttempts + 1;
UpdateMemberProperty(updateMemberDataObject, FailedPasswordAttemptsPropertyTypeAlias, failedAttempts);
// lock user?
if (failedAttempts >= MaxInvalidPasswordAttempts)
{
UpdateMemberProperty(updateMemberDataObject, LockPropertyTypeAlias, 1);
UpdateMemberProperty(updateMemberDataObject, LastLockedOutPropertyTypeAlias, DateTime.Now);
LogHelper.Info<UmbracoMembershipProvider>("Member " + username + " is now locked out, max invalid password attempts exceeded");
}
updateMemberDataObject.Save();
}
}
return (m != null);
}
private static void UpdateMemberProperty(Member m, string propertyTypeAlias, object propertyValue)
{
if (string.IsNullOrEmpty(propertyTypeAlias) == false)
@@ -688,83 +796,7 @@ namespace umbraco.providers.members
return null;
}
/// <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 m = Member.GetMemberFromLoginAndEncodedPassword(username, EncryptOrHashExistingPassword(password));
if (m != null)
{
// check for lock status. If locked, then set the member property to null
if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false)
{
string lockedStatus = GetMemberProperty(m, LockPropertyTypeAlias, true);
if (string.IsNullOrEmpty(lockedStatus) == false)
{
var isLocked = false;
if (bool.TryParse(lockedStatus, out isLocked))
{
if (isLocked)
{
m = null;
}
}
}
}
//check for approve status. If not approved, then set the member property to null
if (m != null && !CheckApproveStatus(m)) {
m = null;
}
// maybe update login date
if (m != null && string.IsNullOrEmpty(LastLoginPropertyTypeAlias) == false)
{
UpdateMemberProperty(m, LastLoginPropertyTypeAlias, DateTime.Now);
}
// maybe reset password attempts
if (m != null && string.IsNullOrEmpty(FailedPasswordAttemptsPropertyTypeAlias) == false)
{
UpdateMemberProperty(m, FailedPasswordAttemptsPropertyTypeAlias, 0);
}
// persist data
if (m != null)
m.Save();
}
else if (string.IsNullOrEmpty(LockPropertyTypeAlias) == false
&& string.IsNullOrEmpty(FailedPasswordAttemptsPropertyTypeAlias) == false)
{
var updateMemberDataObject = Member.GetMemberFromLoginName(username);
// update fail rate if it's approved
if (updateMemberDataObject != null && CheckApproveStatus(updateMemberDataObject))
{
int failedAttempts = 0;
int.TryParse(GetMemberProperty(updateMemberDataObject, FailedPasswordAttemptsPropertyTypeAlias, false), out failedAttempts);
failedAttempts = failedAttempts+1;
UpdateMemberProperty(updateMemberDataObject, FailedPasswordAttemptsPropertyTypeAlias, failedAttempts);
// lock user?
if (failedAttempts >= MaxInvalidPasswordAttempts)
{
UpdateMemberProperty(updateMemberDataObject, LockPropertyTypeAlias, 1);
UpdateMemberProperty(updateMemberDataObject, LastLockedOutPropertyTypeAlias, DateTime.Now);
}
updateMemberDataObject.Save();
}
}
return (m != null);
}
private bool CheckApproveStatus(Member m)
{
var isApproved = false;
@@ -834,7 +866,7 @@ namespace umbraco.providers.members
/// </summary>
/// <param name="password">The password.</param>
/// <returns>The encoded password.</returns>
[Obsolete("Do not use this, it is the legacy way to encode a password")]
[Obsolete("Do not use this, it is the legacy way to encode a password - use the base class EncryptOrHashExistingPassword instead")]
public string EncodePassword(string password)
{
return LegacyEncodePassword(password);
@@ -845,7 +877,7 @@ namespace umbraco.providers.members
/// </summary>
/// <param name="encodedPassword">The encoded password.</param>
/// <returns>The unencoded password.</returns>
[Obsolete("Do not use this, it is the legacy way to decode a password")]
[Obsolete("Do not use this, it is the legacy way to decode a password - use the base class DecodePassword instead")]
public string UnEncodePassword(string encodedPassword)
{
return LegacyUnEncodePassword(encodedPassword);