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:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
13
src/Umbraco.Core/Services/MemberCountType.cs
Normal file
13
src/Umbraco.Core/Services/MemberCountType.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// The types of members to count
|
||||
/// </summary>
|
||||
public enum MemberCountType
|
||||
{
|
||||
All,
|
||||
Online,
|
||||
LockedOut,
|
||||
Approved
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user