Lots more unit tests for the membership providers and some other fixups - have a new failing test as i need to sort out salting issue with encrypted passwords.

This commit is contained in:
Shannon
2013-12-24 14:03:18 +11:00
parent c12b270511
commit edaa5ebd43
8 changed files with 348 additions and 180 deletions

View File

@@ -11,76 +11,6 @@ using Umbraco.Core.Logging;
namespace Umbraco.Core.Security
{
public abstract class UmbracoMembershipProviderBase : MembershipProviderBase
{
protected UmbracoMembershipProviderBase()
{
//Set the defaults!
DefaultMemberTypeAlias = "Member";
}
public string DefaultMemberTypeAlias { get; protected set; }
/// <summary>
/// Adds a new membership user to the data source.
/// </summary>
/// <param name="username">The user name for the new user.</param>
/// <param name="password">The password for the new user.</param>
/// <param name="email">The e-mail address for the new user.</param>
/// <param name="passwordQuestion">The password question for the new user.</param>
/// <param name="passwordAnswer">The password answer for the new user</param>
/// <param name="isApproved">Whether or not the new user is approved to be validated.</param>
/// <param name="providerUserKey">The unique identifier from the membership data source for the user.</param>
/// <param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"></see> enumeration value indicating whether the user was created successfully.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the information for the newly created user.
/// </returns>
protected sealed override MembershipUser PerformCreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
return PerformCreateUser(DefaultMemberTypeAlias, username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
}
/// <summary>
/// Adds a new membership user to the data source.
/// </summary>
/// <param name="memberTypeAlias">The member type alias to use when creating the member</param>
/// <param name="username">The user name for the new user.</param>
/// <param name="password">The password for the new user.</param>
/// <param name="email">The e-mail address for the new user.</param>
/// <param name="passwordQuestion">The password question for the new user.</param>
/// <param name="passwordAnswer">The password answer for the new user</param>
/// <param name="isApproved">Whether or not the new user is approved to be validated.</param>
/// <param name="providerUserKey">The unique identifier from the membership data source for the user.</param>
/// <param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"></see> enumeration value indicating whether the user was created successfully.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the information for the newly created user.
/// </returns>
public MembershipUser CreateUser(string memberTypeAlias, string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
//do the base validation first
base.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
return PerformCreateUser(memberTypeAlias, username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
}
/// <summary>
/// Adds a new membership user to the data source.
/// </summary>
/// <param name="memberTypeAlias">The member type alias to use when creating the member</param>
/// <param name="username">The user name for the new user.</param>
/// <param name="password">The password for the new user.</param>
/// <param name="email">The e-mail address for the new user.</param>
/// <param name="passwordQuestion">The password question for the new user.</param>
/// <param name="passwordAnswer">The password answer for the new user</param>
/// <param name="isApproved">Whether or not the new user is approved to be validated.</param>
/// <param name="providerUserKey">The unique identifier from the membership data source for the user.</param>
/// <param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"></see> enumeration value indicating whether the user was created successfully.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the information for the newly created user.
/// </returns>
protected abstract MembershipUser PerformCreateUser(string memberTypeAlias, string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
}
/// <summary>
/// A base membership provider class offering much of the underlying functionality for initializing and password encryption/hashing.
/// </summary>
@@ -741,7 +671,7 @@ namespace Umbraco.Core.Security
/// <param name="newPassword"></param>
/// <param name="salt"></param>
/// <returns></returns>
protected string EncryptOrHashNewPassword(string newPassword, out string salt)
protected internal string EncryptOrHashNewPassword(string newPassword, out string salt)
{
salt = GenerateSalt();
return EncryptOrHashPassword(newPassword, salt);

View File

@@ -0,0 +1,78 @@
using System.Web.Security;
namespace Umbraco.Core.Security
{
/// <summary>
/// A base membership provider class for umbraco members (not users)
/// </summary>
public abstract class UmbracoMembershipProviderBase : MembershipProviderBase
{
protected UmbracoMembershipProviderBase()
{
//Set the defaults!
DefaultMemberTypeAlias = "Member";
}
public string DefaultMemberTypeAlias { get; protected set; }
/// <summary>
/// Adds a new membership user to the data source.
/// </summary>
/// <param name="username">The user name for the new user.</param>
/// <param name="password">The password for the new user.</param>
/// <param name="email">The e-mail address for the new user.</param>
/// <param name="passwordQuestion">The password question for the new user.</param>
/// <param name="passwordAnswer">The password answer for the new user</param>
/// <param name="isApproved">Whether or not the new user is approved to be validated.</param>
/// <param name="providerUserKey">The unique identifier from the membership data source for the user.</param>
/// <param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"></see> enumeration value indicating whether the user was created successfully.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the information for the newly created user.
/// </returns>
protected sealed override MembershipUser PerformCreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
return PerformCreateUser(DefaultMemberTypeAlias, username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
}
/// <summary>
/// Adds a new membership user to the data source.
/// </summary>
/// <param name="memberTypeAlias">The member type alias to use when creating the member</param>
/// <param name="username">The user name for the new user.</param>
/// <param name="password">The password for the new user.</param>
/// <param name="email">The e-mail address for the new user.</param>
/// <param name="passwordQuestion">The password question for the new user.</param>
/// <param name="passwordAnswer">The password answer for the new user</param>
/// <param name="isApproved">Whether or not the new user is approved to be validated.</param>
/// <param name="providerUserKey">The unique identifier from the membership data source for the user.</param>
/// <param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"></see> enumeration value indicating whether the user was created successfully.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the information for the newly created user.
/// </returns>
public MembershipUser CreateUser(string memberTypeAlias, string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
//do the base validation first
base.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
return PerformCreateUser(memberTypeAlias, username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
}
/// <summary>
/// Adds a new membership user to the data source.
/// </summary>
/// <param name="memberTypeAlias">The member type alias to use when creating the member</param>
/// <param name="username">The user name for the new user.</param>
/// <param name="password">The password for the new user.</param>
/// <param name="email">The e-mail address for the new user.</param>
/// <param name="passwordQuestion">The password question for the new user.</param>
/// <param name="passwordAnswer">The password answer for the new user</param>
/// <param name="isApproved">Whether or not the new user is approved to be validated.</param>
/// <param name="providerUserKey">The unique identifier from the membership data source for the user.</param>
/// <param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"></see> enumeration value indicating whether the user was created successfully.</param>
/// <returns>
/// A <see cref="T:System.Web.Security.MembershipUser"></see> object populated with the information for the newly created user.
/// </returns>
protected abstract MembershipUser PerformCreateUser(string memberTypeAlias, string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
}
}

View File

@@ -8,7 +8,7 @@ namespace Umbraco.Core.Services
/// <summary>
/// Defines the MemberService, which is an easy access to operations involving (umbraco) members.
/// </summary>
internal interface IMemberService : IMembershipMemberService
public interface IMemberService : IMembershipMemberService
{
/// <summary>
/// Checks if a member with the id exists

View File

@@ -10,7 +10,7 @@ namespace Umbraco.Core.Services
/// <remarks>
/// Idea is to have this is an isolated interface so that it can be easily 'replaced' in the membership provider impl.
/// </remarks>
internal interface IMembershipMemberService : IService
public interface IMembershipMemberService : IService
{
/// <summary>
/// Checks if a member with the username exists

View File

@@ -741,6 +741,7 @@
<Compile Include="Security\AuthenticationExtensions.cs" />
<Compile Include="Security\MembershipProviderBase.cs" />
<Compile Include="Security\UmbracoBackOfficeIdentity.cs" />
<Compile Include="Security\UmbracoMembershipProviderBase.cs" />
<Compile Include="Security\UserData.cs" />
<Compile Include="Serialization\AbstractSerializationService.cs" />
<Compile Include="Serialization\Formatter.cs" />

View File

@@ -82,6 +82,7 @@
</system.data>
<system.web>
<machineKey validationKey="5E7B955FCE36F5F2A867C2A0D85DC61E7FEA9E15F1561E8386F78BFE9EE23FF18B21E6A44AA17300B3B9D5DBEB37AA61A2C73884A5BBEDA6D3B14BA408A7A8CD" decryptionKey="116B853D031219E404E088FCA0986D6CF2DFA77E1957B59FCC9404B8CA3909A1" validation="SHA1" decryption="AES" />
<!--<trust level="Medium" originUrl=".*"/>-->
<!-- Sitemap provider-->
<siteMap defaultProvider="UmbracoSiteMapProvider" enabled="true">

View File

@@ -7,8 +7,13 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Security;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers.Entities;
using Umbraco.Web.Security.Providers;
namespace Umbraco.Tests.Membership
@@ -20,31 +25,243 @@ namespace Umbraco.Tests.Membership
//public void Set_Default_Member_Type_On_Init()
//[Test]
//public void Question_Answer_Is_Encrypted()
//public void Create_User_Already_Exists()
//{
//}
//[Test]
//public void Create_User_Requires_Unique_Email()
//{
//}
[Test]
public void Answer_Is_Encrypted()
{
IMember createdMember = null;
var memberType = MockedContentTypes.CreateSimpleMemberType();
foreach (var p in Constants.Conventions.Member.GetStandardPropertyTypeStubs())
{
memberType.AddPropertyType(p.Value);
}
var mServiceMock = new Mock<IMemberService>();
mServiceMock.Setup(service => service.Exists("test")).Returns(false);
mServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
mServiceMock.Setup(
service => service.CreateMember(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Callback((string u, string e, string p, string m) =>
{
createdMember = new Member("test", e, u, p, memberType);
})
.Returns(() => createdMember);
var provider = new MembersMembershipProvider(mServiceMock.Object);
MembershipCreateStatus status;
provider.CreateUser("test", "test", "test", "test@test.com", "test", "test", true, "test", out status);
Assert.AreNotEqual("test", createdMember.PasswordAnswer);
Assert.AreEqual(provider.EncryptString("test"), createdMember.PasswordAnswer);
}
[Test]
public void Password_Encrypted_With_Salt()
{
IMember createdMember = null;
var memberType = MockedContentTypes.CreateSimpleMemberType();
foreach (var p in Constants.Conventions.Member.GetStandardPropertyTypeStubs())
{
memberType.AddPropertyType(p.Value);
}
var mServiceMock = new Mock<IMemberService>();
mServiceMock.Setup(service => service.Exists("test")).Returns(false);
mServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
mServiceMock.Setup(
service => service.CreateMember(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Callback((string u, string e, string p, string m) =>
{
createdMember = new Member("test", e, u, p, memberType);
})
.Returns(() => createdMember);
var provider = new MembersMembershipProvider(mServiceMock.Object);
provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Encrypted" } });
MembershipCreateStatus status;
provider.CreateUser("test", "test", "test", "test@test.com", "test", "test", true, "test", out status);
Assert.AreNotEqual("test", createdMember.Password);
//Assert.AreNotEqual(provider.EncryptString("test"), createdMember.PasswordAnswer);
string salt;
var encodedPassword = provider.EncryptOrHashNewPassword("test", out salt);
Assert.AreEqual(encodedPassword, createdMember.Password);
}
//[Test]
//public void Password_Hashed_With_Salt()
//{
// IMember createdMember = null;
// var memberType = MockedContentTypes.CreateSimpleMemberType();
// foreach (var p in Constants.Conventions.Member.GetStandardPropertyTypeStubs())
// {
// memberType.AddPropertyType(p.Value);
// }
// var mServiceMock = new Mock<IMemberService>();
// mServiceMock.Setup(service => service.Exists("test")).Returns(false);
// mServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
// mServiceMock.Setup(
// service => service.CreateMember(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
// .Callback((string u, string e, string p, string m) =>
// {
// createdMember = new Member("test", e, u, p, memberType);
// })
// .Returns(() => createdMember);
// var provider = new MembersMembershipProvider(mServiceMock.Object);
// provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Hashed" } });
// MembershipCreateStatus status;
// provider.CreateUser("test", "test", "test", "test@test.com", "test", "test", true, "test", out status);
// Assert.AreNotEqual("test", createdMember.Password);
// Assert.AreNotEqual(provider.EncryptString("test"), createdMember.PasswordAnswer);
// string salt;
// var encodedPassword = provider.EncryptOrHashNewPassword("test", out salt);
// Assert.AreEqual(encodedPassword, createdMember.Password);
//}
//[Test]
//public void Password_Encrypted_Validated_With_Salt()
//[Test]
//public void Password_Encrypted_Validated_With_Salt()
}
[TestFixture]
public class MembershipProviderBaseTests
{
//[Test]
//public void Change_Password_Base_Validation()
//[Test]
//public void ChangePasswordQuestionAndAnswer_Base_Validation()
//[Test]
//public void CreateUser_Base_Validation()
[Test]
public void Change_Password_Without_AllowManuallyChangingPassword_And_No_Pass_Validation()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false);
var provider = providerMock.Object;
//[Test]
//public void GetPassword_Base_Validation()
Assert.Throws<NotSupportedException>(() => provider.ChangePassword("test", "", "test"));
}
//[Test]
//public void ResetPassword_Base_Validation()
[Test]
public void Change_Password_With_AllowManuallyChangingPassword_And_Invalid_Creds()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false);
providerMock.Setup(@base => @base.ValidateUser("test", "test")).Returns(false);
var provider = providerMock.Object;
Assert.IsFalse(provider.ChangePassword("test", "test", "test"));
}
[Test]
public void ChangePasswordQuestionAndAnswer_Without_RequiresQuestionAndAnswer()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(false);
var provider = providerMock.Object;
Assert.Throws<NotSupportedException>(() => provider.ChangePasswordQuestionAndAnswer("test", "test", "test", "test"));
}
[Test]
public void ChangePasswordQuestionAndAnswer_Without_AllowManuallyChangingPassword_And_Invalid_Creds()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true);
providerMock.Setup(@base => @base.AllowManuallyChangingPassword).Returns(false);
providerMock.Setup(@base => @base.ValidateUser("test", "test")).Returns(false);
var provider = providerMock.Object;
Assert.IsFalse(provider.ChangePasswordQuestionAndAnswer("test", "test", "test", "test"));
}
[Test]
public void CreateUser_Not_Whitespace()
{
var providerMock = new Mock<MembershipProviderBase>() {CallBase = true};
var provider = providerMock.Object;
MembershipCreateStatus status;
var result = provider.CreateUser("", "", "test@test.com", "", "", true, "", out status);
Assert.IsNull(result);
Assert.AreEqual(MembershipCreateStatus.InvalidUserName, status);
}
[Test]
public void CreateUser_Invalid_Question()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true);
var provider = providerMock.Object;
MembershipCreateStatus status;
var result = provider.CreateUser("test", "test", "test@test.com", "", "", true, "", out status);
Assert.IsNull(result);
Assert.AreEqual(MembershipCreateStatus.InvalidQuestion, status);
}
[Test]
public void CreateUser_Invalid_Answer()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true);
var provider = providerMock.Object;
MembershipCreateStatus status;
var result = provider.CreateUser("test", "test", "test@test.com", "test", "", true, "", out status);
Assert.IsNull(result);
Assert.AreEqual(MembershipCreateStatus.InvalidAnswer, status);
}
[Test]
public void GetPassword_Without_EnablePasswordRetrieval()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.EnablePasswordRetrieval).Returns(false);
var provider = providerMock.Object;
Assert.Throws<ProviderException>(() => provider.GetPassword("test", "test"));
}
[Test]
public void GetPassword_With_Hashed()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.EnablePasswordRetrieval).Returns(true);
providerMock.Setup(@base => @base.PasswordFormat).Returns(MembershipPasswordFormat.Hashed);
var provider = providerMock.Object;
Assert.Throws<ProviderException>(() => provider.GetPassword("test", "test"));
}
[Test]
public void ResetPassword_Without_EnablePasswordReset()
{
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
providerMock.Setup(@base => @base.EnablePasswordReset).Returns(false);
var provider = providerMock.Object;
Assert.Throws<NotSupportedException>(() => provider.ResetPassword("test", "test"));
}
[Test]
public void Sets_Defaults()
{
var provider = new TestProvider();
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
var provider = providerMock.Object;
provider.Initialize("test", new NameValueCollection());
Assert.AreEqual("test", provider.Name);
@@ -65,7 +282,8 @@ namespace Umbraco.Tests.Membership
[Test]
public void Throws_Exception_With_Hashed_Password_And_Password_Retrieval()
{
var provider = new TestProvider();
var providerMock = new Mock<MembershipProviderBase>() { CallBase = true };
var provider = providerMock.Object;
Assert.Throws<ProviderException>(() => provider.Initialize("test", new NameValueCollection()
{
@@ -125,88 +343,5 @@ namespace Umbraco.Tests.Membership
Assert.AreEqual(salt, initSalt);
}
private class TestProvider : MembershipProviderBase
{
public override void UpdateUser(MembershipUser user)
{
throw new NotImplementedException();
}
public override bool ValidateUser(string username, string password)
{
throw new NotImplementedException();
}
public override bool UnlockUser(string userName)
{
throw new NotImplementedException();
}
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
throw new NotImplementedException();
}
public override MembershipUser GetUser(string username, bool userIsOnline)
{
throw new NotImplementedException();
}
public override string GetUserNameByEmail(string email)
{
throw new NotImplementedException();
}
public override bool DeleteUser(string username, bool deleteAllRelatedData)
{
throw new NotImplementedException();
}
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
public override int GetNumberOfUsersOnline()
{
throw new NotImplementedException();
}
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
protected override bool PerformChangePassword(string username, string oldPassword, string newPassword)
{
throw new NotImplementedException();
}
protected override bool PerformChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
{
throw new NotImplementedException();
}
protected override MembershipUser PerformCreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
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

@@ -6,6 +6,7 @@ using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.Security;
using Umbraco.Core;
@@ -30,6 +31,15 @@ namespace Umbraco.Web.Security.Providers
get { return _memberService ?? (_memberService = ApplicationContext.Current.Services.MemberService); }
}
public MembersMembershipProvider()
{
}
internal MembersMembershipProvider(IMemberService memberService)
{
_memberService = memberService;
}
public string ProviderName
{
get { return "MembersMembershipProvider"; }
@@ -80,7 +90,7 @@ namespace Umbraco.Web.Security.Providers
// This is allowed based on the overridden AllowManuallyChangingPassword option.
// in order to support updating passwords from the umbraco core, we can't validate the old password
var m = _memberService.GetByUsername(username);
var m = MemberService.GetByUsername(username);
if (m == null) return false;
string salt;
@@ -88,8 +98,8 @@ namespace Umbraco.Web.Security.Providers
m.Password = FormatPasswordForStorage(encodedPassword, salt);
m.LastPasswordChangeDate = DateTime.Now;
_memberService.Save(m);
MemberService.Save(m);
return true;
}
@@ -113,7 +123,7 @@ namespace Umbraco.Web.Security.Providers
}
member.PasswordQuestion = newPasswordQuestion;
member.PasswordAnswer = newPasswordAnswer;
member.PasswordAnswer = EncryptString(newPasswordAnswer);
MemberService.Save(member);
@@ -158,10 +168,14 @@ namespace Umbraco.Web.Security.Providers
string salt;
var encodedPassword = EncryptOrHashNewPassword(password, out salt);
var member = MemberService.CreateMember(email, username, encodedPassword, memberTypeAlias);
var member = MemberService.CreateMember(
email,
username,
FormatPasswordForStorage(encodedPassword, salt),
memberTypeAlias);
member.PasswordQuestion = passwordQuestion;
member.PasswordAnswer = passwordAnswer;
member.PasswordAnswer = EncryptString(passwordAnswer);
member.IsApproved = isApproved;
member.LastLoginDate = DateTime.Now;
member.LastPasswordChangeDate = DateTime.Now;
@@ -289,9 +303,9 @@ namespace Umbraco.Web.Security.Providers
throw new ProviderException("The supplied user is not found");
}
//TODO: We need to encrypt the answer here to match against the encrypted answer in the database
var encAnswer = EncryptString(answer);
if (RequiresQuestionAndAnswer && m.PasswordAnswer != answer)
if (RequiresQuestionAndAnswer && m.PasswordAnswer != encAnswer)
{
throw new ProviderException("Incorrect password answer");
}
@@ -301,6 +315,15 @@ namespace Umbraco.Web.Security.Providers
return decodedPassword;
}
internal string EncryptString(string str)
{
var bytes = Encoding.Unicode.GetBytes(str);
var password = new byte[bytes.Length];
Buffer.BlockCopy(bytes, 0, password, 0, bytes.Length);
var encBytes = EncryptPassword(password, MembershipPasswordCompatibilityMode.Framework40);
return Convert.ToBase64String(encBytes);
}
/// <summary>
/// Gets information from the data source for a user. Provides an option to update the last-activity date/time stamp for the user.
/// </summary>
@@ -395,16 +418,16 @@ namespace Umbraco.Web.Security.Providers
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
var encAnswer = EncryptString(answer);
if (RequiresQuestionAndAnswer && m.PasswordAnswer != answer)
if (RequiresQuestionAndAnswer && m.PasswordAnswer != encAnswer)
{
throw new ProviderException("Incorrect password answer");
}
string salt;
var encodedPassword = EncryptOrHashNewPassword(generatedPassword, out salt);
m.Password = encodedPassword;
m.Password = FormatPasswordForStorage(encodedPassword, salt);
m.LastPasswordChangeDate = DateTime.Now;
MemberService.Save(m);