Removes references to password question/answer

This commit is contained in:
Shannon
2019-11-25 23:53:12 +11:00
parent 76b413e527
commit a458df360f
19 changed files with 13 additions and 232 deletions

View File

@@ -137,21 +137,7 @@ namespace Umbraco.Core
public static readonly string UmbracoMemberProviderName = "UmbracoMembershipProvider";
public static readonly string UmbracoRoleProviderName = "UmbracoRoleProvider";
/// <summary>
/// Property alias for a Members Password Question
/// </summary>
public const string PasswordQuestion = "umbracoMemberPasswordRetrievalQuestion";
public const string PasswordQuestionLabel = "Password Question";
/// <summary>
/// Property alias for Members Password Answer
/// </summary>
public const string PasswordAnswer = "umbracoMemberPasswordRetrievalAnswer";
public const string PasswordAnswerLabel = "Password Answer";
/// <summary>
/// Property alias for the Comments on a Member
/// </summary>

View File

@@ -8,23 +8,13 @@ namespace Umbraco.Core.Models.Membership
/// </summary>
public interface IMembershipUser : IEntity
{
object ProviderUserKey { get; set; } // fixme: This will be obsolete when we remove membership providers
string Username { get; set; }
string Email { get; set; }
/// <summary>
/// Gets or sets the raw password value
/// </summary>
string RawPasswordValue { get; set; } // fixme: This will be obsolete when we remove membership providers
string PasswordQuestion { get; set; } // fixme: This will be obsolete when we remove membership providers
/// <summary>
/// Gets or sets the raw password answer value
/// </summary>
string RawPasswordAnswerValue { get; set; } // fixme: This will be obsolete when we remove membership providers
string RawPasswordValue { get; set; }
string Comments { get; set; }
bool IsApproved { get; set; }

View File

@@ -67,24 +67,6 @@ namespace Umbraco.Core
Name = Constants.Conventions.Member.LastPasswordChangeDateLabel,
DataTypeId = Constants.DataTypes.LabelDateTime
}
},
{
Constants.Conventions.Member.PasswordAnswer,
new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true,
Constants.Conventions.Member.PasswordAnswer)
{
Name = Constants.Conventions.Member.PasswordAnswerLabel,
DataTypeId = Constants.DataTypes.LabelString
}
},
{
Constants.Conventions.Member.PasswordQuestion,
new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true,
Constants.Conventions.Member.PasswordQuestion)
{
Name = Constants.Conventions.Member.PasswordQuestionLabel,
DataTypeId = Constants.DataTypes.LabelString
}
}
};
}

View File

@@ -229,9 +229,6 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 35, UniqueId = 35.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.PasswordQuestion, Name = Constants.Conventions.Member.PasswordQuestionLabel, SortOrder = 7, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 36, UniqueId = 36.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.PasswordAnswer, Name = Constants.Conventions.Member.PasswordAnswerLabel, SortOrder = 8, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
}
private void CreateLanguageData()

View File

@@ -166,66 +166,6 @@ namespace Umbraco.Core.Models
// * Check if we are using the umbraco membership provider, if so then we need to use the configured fields - not the explicit fields below
// * If any of the fields don't exist, what should we do? Currently it will throw an exception!
/// <summary>
/// Gets or sets the Password Question
/// </summary>
/// <remarks>
/// Alias: umbracoMemberPasswordRetrievalQuestion
/// Part of the standard properties collection.
/// </remarks>
[DataMember]
public string PasswordQuestion
{
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.PasswordQuestion, "PasswordQuestion", default(string));
if (a.Success == false) return a.Result;
return Properties[Constants.Conventions.Member.PasswordQuestion].GetValue() == null
? string.Empty
: Properties[Constants.Conventions.Member.PasswordQuestion].GetValue().ToString();
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.PasswordQuestion,
"PasswordQuestion") == false) return;
Properties[Constants.Conventions.Member.PasswordQuestion].SetValue(value);
}
}
/// <summary>
/// Gets or sets the raw password answer value
/// </summary>
/// <remarks>
/// For security reasons this value should be encrypted, the encryption process is handled by the membership provider
/// Alias: umbracoMemberPasswordRetrievalAnswer
///
/// Part of the standard properties collection.
/// </remarks>
[IgnoreDataMember]
public string RawPasswordAnswerValue
{
get
{
var a = WarnIfPropertyTypeNotFoundOnGet(Constants.Conventions.Member.PasswordAnswer, "PasswordAnswer", default(string));
if (a.Success == false) return a.Result;
return Properties[Constants.Conventions.Member.PasswordAnswer].GetValue() == null
? string.Empty
: Properties[Constants.Conventions.Member.PasswordAnswer].GetValue().ToString();
}
set
{
if (WarnIfPropertyTypeNotFoundOnSet(
Constants.Conventions.Member.PasswordAnswer,
"PasswordAnswer") == false) return;
Properties[Constants.Conventions.Member.PasswordAnswer].SetValue(value);
}
}
/// <summary>
/// Gets or set the comments for the member
/// </summary>

View File

@@ -41,8 +41,6 @@ namespace Umbraco.Core.Persistence.Mappers
DefineMap<Member, PropertyDataDto>(nameof(Member.IsApproved), nameof(PropertyDataDto.IntegerValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.IsLockedOut), nameof(PropertyDataDto.IntegerValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.Comments), nameof(PropertyDataDto.TextValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.RawPasswordAnswerValue), nameof(PropertyDataDto.VarcharValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.PasswordQuestion), nameof(PropertyDataDto.VarcharValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.FailedPasswordAttempts), nameof(PropertyDataDto.IntegerValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.LastLockoutDate), nameof(PropertyDataDto.DateValue));
DefineMap<Member, PropertyDataDto>(nameof(Member.LastLoginDate), nameof(PropertyDataDto.DateValue));

View File

@@ -233,10 +233,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IMember entity)
{
if (entity.ProviderUserKey == null)
{
entity.ProviderUserKey = entity.Key;
}
entity.AddingEntity();
var member = (Member) entity;

View File

@@ -16,8 +16,6 @@ namespace Umbraco.Core.Security
string CommentPropertyTypeAlias { get; }
string LastLoginPropertyTypeAlias { get; }
string LastPasswordChangedPropertyTypeAlias { get; }
string PasswordRetrievalQuestionPropertyTypeAlias { get; }
string PasswordRetrievalAnswerPropertyTypeAlias { get; }
}
}

View File

@@ -1235,13 +1235,6 @@ namespace Umbraco.Core.Services.Implement
foreach (var property in member.Properties)
{
//ignore list
switch (property.Alias)
{
case Constants.Conventions.Member.PasswordQuestion:
continue;
}
var propertyExportModel = new MemberExportProperty
{
Id = property.Id,

View File

@@ -74,38 +74,6 @@ namespace Umbraco.Tests.Membership
Assert.IsNull(user);
}
[Test]
public void Answer_Is_Encrypted()
{
IMember createdMember = null;
var memberType = MockedContentTypes.CreateSimpleMemberType();
foreach (var p in ConventionsHelper.GetStandardPropertyTypeStubs())
{
memberType.AddPropertyType(p.Value);
}
var memberTypeServiceMock = new Mock<IMemberTypeService>();
memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Member");
var membershipServiceMock = new Mock<IMembershipMemberService>();
membershipServiceMock.Setup(service => service.Exists("test")).Returns(false);
membershipServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null);
membershipServiceMock.Setup(
service => service.CreateWithIdentity(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
.Callback((string u, string e, string p, string m, bool isApproved) =>
{
createdMember = new Member("test", e, u, p, memberType, isApproved);
})
.Returns(() => createdMember);
var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion());
provider.Initialize("test", new NameValueCollection());
MembershipCreateStatus status;
provider.CreateUser("test", "test", "testtest$1", "test@test.com", "test", "test", true, "test", out status);
Assert.AreNotEqual("test", createdMember.RawPasswordAnswerValue);
Assert.AreEqual(provider.EncryptString("test"), createdMember.RawPasswordAnswerValue);
}
[Test]
public void Password_Encrypted()
{

View File

@@ -50,9 +50,7 @@ namespace Umbraco.Tests.Models
member.LastLockoutDate = DateTime.Now;
member.LastLoginDate = DateTime.Now;
member.LastPasswordChangeDate = DateTime.Now;
member.PasswordQuestion = "question";
member.ProviderUserKey = Guid.NewGuid();
member.RawPasswordAnswerValue = "raw answer";
member.RawPasswordValue = "raw pass";
member.SortOrder = 5;
member.Trashed = false;
@@ -89,9 +87,7 @@ namespace Umbraco.Tests.Models
Assert.AreEqual(clone.Trashed, member.Trashed);
Assert.AreEqual(clone.UpdateDate, member.UpdateDate);
Assert.AreEqual(clone.VersionId, member.VersionId);
Assert.AreEqual(clone.PasswordQuestion, member.PasswordQuestion);
Assert.AreEqual(clone.ProviderUserKey, member.ProviderUserKey);
Assert.AreEqual(clone.RawPasswordAnswerValue, member.RawPasswordAnswerValue);
Assert.AreEqual(clone.RawPasswordValue, member.RawPasswordValue);
Assert.AreNotSame(clone.Properties, member.Properties);
Assert.AreEqual(clone.Properties.Count(), member.Properties.Count());
@@ -137,9 +133,7 @@ namespace Umbraco.Tests.Models
member.LastLockoutDate = DateTime.Now;
member.LastLoginDate = DateTime.Now;
member.LastPasswordChangeDate = DateTime.Now;
member.PasswordQuestion = "question";
member.ProviderUserKey = Guid.NewGuid();
member.RawPasswordAnswerValue = "raw answer";
member.RawPasswordValue = "raw pass";
member.SortOrder = 5;
member.Trashed = false;

View File

@@ -65,7 +65,6 @@ namespace Umbraco.Web.Models.Mapping
target.LastLockoutDate = source.LastLockoutDate;
target.LastLoginDate = source.LastLoginDate;
target.LastPasswordChangeDate = source.LastPasswordChangedDate;
target.ProviderUserKey = source.ProviderUserKey;
target.RawPasswordValue = source.CreationDate > DateTime.MinValue ? Guid.NewGuid().ToString("N") : "";
target.UpdateDate = source.LastActivityDate;
target.Username = source.UserName;

View File

@@ -10,7 +10,6 @@ namespace Umbraco.Web.Models.Membership
private readonly IMembershipUser _member;
private readonly string _userName;
private readonly object _providerUserKey;
private readonly string _passwordQuestion;
private readonly bool _isLockedOut;
private readonly DateTime _lastLockoutDate;
private readonly DateTime _creationDate;
@@ -26,7 +25,7 @@ namespace Umbraco.Web.Models.Membership
//NOTE: We are not calling the base constructor which will validate that a provider with the specified name exists which causes issues with unit tests. The ctor
// validation for that doesn't need to be there anyways (have checked the source).
public UmbracoMembershipMember(IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
public UmbracoMembershipMember(IMembershipUser member, string providerName)
{
_member = member;
//NOTE: We are copying the values here so that everything is consistent with how the underlying built-in ASP.Net membership user
@@ -34,11 +33,9 @@ namespace Umbraco.Web.Models.Membership
if (member.Username != null)
_userName = member.Username.Trim();
if (member.Email != null)
_email = member.Email.Trim();
if (member.PasswordQuestion != null)
_passwordQuestion = member.PasswordQuestion.Trim();
_email = member.Email.Trim();
_providerName = providerName;
_providerUserKey = providerKeyAsGuid ? member.ProviderUserKey : member.Id;
_providerUserKey = member.Key;
_comment = member.Comments;
_isApproved = member.IsApproved;
_isLockedOut = member.IsLockedOut;
@@ -71,10 +68,7 @@ namespace Umbraco.Web.Models.Membership
set { _email = value; }
}
public override string PasswordQuestion
{
get { return _passwordQuestion; }
}
public override string PasswordQuestion => string.Empty;
public override string Comment
{

View File

@@ -76,7 +76,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
// see also PublishedContentType
AddIf(contentType, properties, "Email", member.Email);
AddIf(contentType, properties, "Username", member.Username);
AddIf(contentType, properties, "PasswordQuestion", member.PasswordQuestion);
AddIf(contentType, properties, "Comments", member.Comments);
AddIf(contentType, properties, "IsApproved", member.IsApproved);
AddIf(contentType, properties, "IsLockedOut", member.IsLockedOut);
@@ -103,8 +102,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
public string UserName => _member.Username;
public string PasswordQuestion => _member.PasswordQuestion;
public string Comments => _member.Comments;
public bool IsApproved => _member.IsApproved;

View File

@@ -51,8 +51,6 @@ namespace Umbraco.Web.PublishedCache
public string UserName => _membershipUser.Username;
public string PasswordQuestion => _membershipUser.PasswordQuestion;
public string Comments => _membershipUser.Comments;
public bool IsApproved => _membershipUser.IsApproved;
@@ -98,7 +96,6 @@ namespace Umbraco.Web.PublishedCache
EnsureMemberProperty(properties, aliases, "Email", Email);
EnsureMemberProperty(properties, aliases, "UserName", UserName);
EnsureMemberProperty(properties, aliases, "PasswordQuestion", PasswordQuestion);
EnsureMemberProperty(properties, aliases, "Comments", Comments);
EnsureMemberProperty(properties, aliases, "IsApproved", IsApproved);
EnsureMemberProperty(properties, aliases, "IsLockedOut", IsLockedOut);

View File

@@ -74,7 +74,6 @@ namespace Umbraco.Web.Security
private int _passwordAttemptWindow;
private MembershipPasswordFormat _passwordFormat;
private string _passwordStrengthRegularExpression;
private bool _requiresQuestionAndAnswer;
private bool _requiresUniqueEmail;
public bool UseLegacyEncoding { get; private set; }
@@ -164,14 +163,9 @@ namespace Umbraco.Web.Security
}
/// <summary>
/// Gets a value indicating whether the membership provider is configured to require the user to answer a password question for password reset and retrieval.
/// Always returns false, question/answer is not supported
/// </summary>
/// <value></value>
/// <returns>true if a password answer is required for password reset and retrieval; otherwise, false. The default is true.</returns>
public override bool RequiresQuestionAndAnswer
{
get { return _requiresQuestionAndAnswer; }
}
public override bool RequiresQuestionAndAnswer => false;
/// <summary>
/// Gets a value indicating whether the membership provider is configured to require a unique e-mail address for each user name.
@@ -225,7 +219,6 @@ namespace Umbraco.Web.Security
_enablePasswordRetrieval = config.GetValue("enablePasswordRetrieval", false);
_enablePasswordReset = config.GetValue("enablePasswordReset", true);
_requiresQuestionAndAnswer = config.GetValue("requiresQuestionAndAnswer", false);
_requiresUniqueEmail = config.GetValue("requiresUniqueEmail", true);
_maxInvalidPasswordAttempts = GetIntValue(config, "maxInvalidPasswordAttempts", 5, false, 0);
_passwordAttemptWindow = GetIntValue(config, "passwordAttemptWindow", 10, false, 0);
@@ -695,7 +688,7 @@ namespace Umbraco.Web.Security
sb.AppendLine("_passwordAttemptWindow=" + _passwordAttemptWindow);
sb.AppendLine("_passwordFormat=" + _passwordFormat);
sb.AppendLine("_passwordStrengthRegularExpression=" + _passwordStrengthRegularExpression);
sb.AppendLine("_requiresQuestionAndAnswer=" + _requiresQuestionAndAnswer);
sb.AppendLine("_requiresQuestionAndAnswer=" + RequiresQuestionAndAnswer);
sb.AppendLine("_requiresUniqueEmail=" + _requiresUniqueEmail);
return sb.ToString();
}

View File

@@ -17,9 +17,9 @@ namespace Umbraco.Web.Security
public static class MembershipProviderExtensions
{
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName, bool providerKeyAsGuid = false)
internal static UmbracoMembershipMember AsConcreteMembershipUser(this IMembershipUser member, string providerName)
{
var membershipMember = new UmbracoMembershipMember(member, providerName, providerKeyAsGuid);
var membershipMember = new UmbracoMembershipMember(member, providerName);
return membershipMember;
}

View File

@@ -31,8 +31,6 @@ namespace Umbraco.Web.Security.Providers
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;
_memberTypeService = memberTypeService;
}
@@ -40,13 +38,12 @@ namespace Umbraco.Web.Security.Providers
private string _defaultMemberTypeAlias = "Member";
private volatile bool _hasDefaultMember;
private static readonly object Locker = new object();
private bool _providerKeyAsGuid;
public override string ProviderName => "MembersMembershipProvider";
protected override MembershipUser ConvertToMembershipUser(IMember entity)
{
return entity.AsConcreteMembershipUser(Name, _providerKeyAsGuid);
return entity.AsConcreteMembershipUser(Name);
}
public string LockPropertyTypeAlias { get; }
@@ -56,8 +53,6 @@ namespace Umbraco.Web.Security.Providers
public string CommentPropertyTypeAlias { get; }
public string LastLoginPropertyTypeAlias { get; }
public string LastPasswordChangedPropertyTypeAlias { get; }
public string PasswordRetrievalQuestionPropertyTypeAlias { get; }
public string PasswordRetrievalAnswerPropertyTypeAlias { get; }
public override void Initialize(string name, NameValueCollection config)
{
@@ -74,15 +69,6 @@ namespace Umbraco.Web.Security.Providers
_hasDefaultMember = true;
}
//devs can configure the provider user key to be a guid if they want, by default it is int
if (config["providerKeyType"] != null)
{
if (config["providerKeyType"] == "guid")
{
_providerKeyAsGuid = true;
}
}
// these need to be lazy else we get a stack overflow since we cannot access Membership.HashAlgorithmType without initializing the providers
_passwordConfig = new Lazy<IPasswordConfiguration>(() => new MembershipProviderPasswordConfiguration(

View File

@@ -113,18 +113,7 @@ namespace Umbraco.Web.Security.Providers
/// </returns>
protected override bool PerformChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
{
var member = MemberService.GetByUsername(username);
if (member == null)
{
return false;
}
member.PasswordQuestion = newPasswordQuestion;
member.RawPasswordAnswerValue = EncryptString(newPasswordAnswer);
MemberService.Save(member);
return true;
throw new NotSupportedException("Password question/answer is not supported");
}
/// <summary>
@@ -171,8 +160,6 @@ namespace Umbraco.Web.Security.Providers
memberTypeAlias,
isApproved);
member.PasswordQuestion = passwordQuestion;
member.RawPasswordAnswerValue = EncryptString(passwordAnswer);
member.LastLoginDate = DateTime.Now;
member.LastPasswordChangeDate = DateTime.Now;
@@ -305,13 +292,6 @@ namespace Umbraco.Web.Security.Providers
throw new ProviderException("The supplied user is not found");
}
var encAnswer = EncryptString(answer);
if (RequiresQuestionAndAnswer && m.RawPasswordAnswerValue != encAnswer)
{
throw new ProviderException("Incorrect password answer");
}
var decodedPassword = DecryptPassword(m.RawPasswordValue);
return decodedPassword;
@@ -432,13 +412,6 @@ namespace Umbraco.Web.Security.Providers
throw new ProviderException("The member is locked out.");
}
var encAnswer = EncryptString(answer);
if (RequiresQuestionAndAnswer && m.RawPasswordAnswerValue != encAnswer)
{
throw new ProviderException("Incorrect password answer");
}
string salt;
var encodedPassword = PasswordSecurity.EncryptOrHashNewPassword(generatedPassword, out salt);
m.RawPasswordValue = PasswordSecurity.FormatPasswordForStorage(encodedPassword, salt);