Merge remote-tracking branch 'origin/6.2.0-membershipprovider' into 7.0.0
Conflicts: src/Umbraco.Web.UI/umbraco/controls/passwordChanger.ascx src/Umbraco.Web/Security/WebSecurity.cs src/umbraco.providers/UsersMembershipProvider.cs src/umbraco.providers/members/MembersMembershipProvider.cs
This commit is contained in:
@@ -15,6 +15,40 @@ namespace Umbraco.Core.Security
|
||||
/// </summary>
|
||||
public abstract class MembershipProviderBase : MembershipProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Providers can override this setting, default is 7
|
||||
/// </summary>
|
||||
protected virtual int DefaultMinPasswordLength
|
||||
{
|
||||
get { return 7; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Providers can override this setting, default is 1
|
||||
/// </summary>
|
||||
protected virtual int DefaultMinNonAlphanumericChars
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Providers can override this setting, default is false to use better security
|
||||
/// </summary>
|
||||
protected virtual bool DefaultUseLegacyEncoding
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Providers can override this setting, by default this is false which means that the provider will
|
||||
/// authenticate the username + password when ChangePassword is called. This property exists purely for
|
||||
/// backwards compatibility.
|
||||
/// </summary>
|
||||
internal virtual bool AllowManuallyChangingPassword
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private string _applicationName;
|
||||
private bool _enablePasswordReset;
|
||||
private bool _enablePasswordRetrieval;
|
||||
@@ -177,8 +211,8 @@ namespace Umbraco.Core.Security
|
||||
_requiresUniqueEmail = config.GetValue("requiresUniqueEmail", false);
|
||||
_maxInvalidPasswordAttempts = GetIntValue(config, "maxInvalidPasswordAttempts", 5, false, 0);
|
||||
_passwordAttemptWindow = GetIntValue(config, "passwordAttemptWindow", 10, false, 0);
|
||||
_minRequiredPasswordLength = GetIntValue(config, "minRequiredPasswordLength", 7, true, 0x80);
|
||||
_minRequiredNonAlphanumericCharacters = GetIntValue(config, "minRequiredNonalphanumericCharacters", 1, true, 0x80);
|
||||
_minRequiredPasswordLength = GetIntValue(config, "minRequiredPasswordLength", DefaultMinPasswordLength, true, 0x80);
|
||||
_minRequiredNonAlphanumericCharacters = GetIntValue(config, "minRequiredNonalphanumericCharacters", DefaultMinNonAlphanumericChars, true, 0x80);
|
||||
_passwordStrengthRegularExpression = config["passwordStrengthRegularExpression"];
|
||||
|
||||
_applicationName = config["applicationName"];
|
||||
@@ -186,7 +220,7 @@ namespace Umbraco.Core.Security
|
||||
_applicationName = GetDefaultAppName();
|
||||
|
||||
//by default we will continue using the legacy encoding.
|
||||
_useLegacyEncoding = config.GetValue("useLegacyEncoding", true);
|
||||
_useLegacyEncoding = config.GetValue("useLegacyEncoding", DefaultUseLegacyEncoding);
|
||||
|
||||
// make sure password format is clear by default.
|
||||
string str = config["passwordFormat"] ?? "Clear";
|
||||
@@ -238,6 +272,26 @@ namespace Umbraco.Core.Security
|
||||
Strength
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to ensure the AllowManuallyChangingPassword rule is adhered to
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="oldPassword"></param>
|
||||
/// <param name="newPassword"></param>
|
||||
/// <returns></returns>
|
||||
public sealed override bool ChangePassword(string username, string oldPassword, string newPassword)
|
||||
{
|
||||
if (oldPassword.IsNullOrWhiteSpace() && AllowManuallyChangingPassword == false)
|
||||
{
|
||||
//If the old password is empty and AllowManuallyChangingPassword is false, than this provider cannot just arbitrarily change the password
|
||||
throw new NotSupportedException("This provider does not support manually changing the password");
|
||||
}
|
||||
|
||||
return PerformChangePassword(username, oldPassword, newPassword);
|
||||
}
|
||||
|
||||
protected abstract bool PerformChangePassword(string username, string oldPassword, string newPassword);
|
||||
|
||||
protected internal static Attempt<PasswordValidityError> IsPasswordValid(string password, int minRequiredNonAlphanumericChars, string strengthRegex, int minLength)
|
||||
{
|
||||
if (minRequiredNonAlphanumericChars > 0)
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
</asp:PlaceHolder>
|
||||
|
||||
<div id="passwordInputArea">
|
||||
<asp:PlaceHolder runat="server" ID="CurrentPasswordPlaceHolder" Visible="<%#Provider.EnablePasswordRetrieval == false %>">
|
||||
<asp:PlaceHolder runat="server" ID="CurrentPasswordPlaceHolder" Visible="<%#ShowOldPassword %>">
|
||||
<div class="umb-el-wrap ">
|
||||
<label class="control-label" for="<%=umbPasswordChanger_passwordCurrent.ClientID %>"><%=umbraco.ui.GetText("user", "passwordCurrent")%></label>
|
||||
<div class="controls controls-row">
|
||||
|
||||
@@ -232,78 +232,95 @@ namespace Umbraco.Web.Security
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not reset password, error: " + ex.Message + " (see log for full details)", new[] { "resetPassword" }) });
|
||||
}
|
||||
}
|
||||
if (passwordModel.NewPassword.IsNullOrWhiteSpace() == false)
|
||||
|
||||
//we're not resetting it so we need to try to change it.
|
||||
|
||||
if (passwordModel.NewPassword.IsNullOrWhiteSpace())
|
||||
{
|
||||
//we're not resetting it so we need to try to change it.
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Cannot set an empty password", new[] { "value" }) });
|
||||
}
|
||||
|
||||
if (passwordModel.OldPassword.IsNullOrWhiteSpace() && membershipProvider.EnablePasswordRetrieval == false)
|
||||
//This is an edge case and is only necessary for backwards compatibility:
|
||||
var umbracoBaseProvider = membershipProvider as MembershipProviderBase;
|
||||
if (umbracoBaseProvider != null && umbracoBaseProvider.AllowManuallyChangingPassword)
|
||||
{
|
||||
//this provider allows manually changing the password without the old password, so we can just do it
|
||||
try
|
||||
{
|
||||
//if password retrieval is not enabled but there is no old password we cannot continue
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "value" }) });
|
||||
var result = umbracoBaseProvider.ChangePassword(username, "", passwordModel.NewPassword);
|
||||
return result == false
|
||||
? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "value" }) })
|
||||
: Attempt.Succeed(new PasswordChangedModel());
|
||||
}
|
||||
if (passwordModel.OldPassword.IsNullOrWhiteSpace() == false)
|
||||
catch (Exception ex)
|
||||
{
|
||||
//if an old password is suplied try to change it
|
||||
|
||||
try
|
||||
{
|
||||
var result = membershipProvider.ChangePassword(username, passwordModel.OldPassword, passwordModel.NewPassword);
|
||||
if (result == false)
|
||||
{
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "value" }) });
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WarnWithException<WebSecurity>("Could not change member password", ex);
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) });
|
||||
}
|
||||
}
|
||||
else if (membershipProvider.EnablePasswordRetrieval == false)
|
||||
{
|
||||
//we cannot continue if we cannot get the current password
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "value" }) });
|
||||
}
|
||||
else if (membershipProvider.RequiresQuestionAndAnswer && passwordModel.Answer.IsNullOrWhiteSpace())
|
||||
{
|
||||
//if the question answer is required but there isn't one, we cannot continue
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the password answer", new[] { "value" }) });
|
||||
}
|
||||
else
|
||||
{
|
||||
//lets try to get the old one so we can change it
|
||||
|
||||
try
|
||||
{
|
||||
var oldPassword = membershipProvider.GetPassword(
|
||||
username,
|
||||
membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null);
|
||||
|
||||
try
|
||||
{
|
||||
var result = membershipProvider.ChangePassword(username, oldPassword, passwordModel.NewPassword);
|
||||
if (result == false)
|
||||
{
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password", new[] { "value" }) });
|
||||
}
|
||||
}
|
||||
catch (Exception ex1)
|
||||
{
|
||||
LogHelper.WarnWithException<WebSecurity>("Could not change member password", ex1);
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex1.Message + " (see log for full details)", new[] { "value" }) });
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
LogHelper.WarnWithException<WebSecurity>("Could not retrieve member password", ex2);
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex2.Message + " (see log for full details)", new[] { "value" }) });
|
||||
}
|
||||
LogHelper.WarnWithException<WebSecurity>("Could not change member password", ex);
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) });
|
||||
}
|
||||
}
|
||||
|
||||
//woot!
|
||||
return Attempt.Succeed(new PasswordChangedModel());
|
||||
//The provider does not support manually chaning the password but no old password supplied - need to return an error
|
||||
if (passwordModel.OldPassword.IsNullOrWhiteSpace() && membershipProvider.EnablePasswordRetrieval == false)
|
||||
{
|
||||
//if password retrieval is not enabled but there is no old password we cannot continue
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "value" }) });
|
||||
}
|
||||
|
||||
if (passwordModel.OldPassword.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
//if an old password is suplied try to change it
|
||||
|
||||
try
|
||||
{
|
||||
var result = membershipProvider.ChangePassword(username, passwordModel.OldPassword, passwordModel.NewPassword);
|
||||
return result == false
|
||||
? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, invalid username or password", new[] { "value" }) })
|
||||
: Attempt.Succeed(new PasswordChangedModel());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WarnWithException<WebSecurity>("Could not change member password", ex);
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) });
|
||||
}
|
||||
}
|
||||
|
||||
if (membershipProvider.EnablePasswordRetrieval == false)
|
||||
{
|
||||
//we cannot continue if we cannot get the current password
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the old password", new[] { "value" }) });
|
||||
}
|
||||
if (membershipProvider.RequiresQuestionAndAnswer && passwordModel.Answer.IsNullOrWhiteSpace())
|
||||
{
|
||||
//if the question answer is required but there isn't one, we cannot continue
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Password cannot be changed without the password answer", new[] { "value" }) });
|
||||
}
|
||||
|
||||
//lets try to get the old one so we can change it
|
||||
try
|
||||
{
|
||||
var oldPassword = membershipProvider.GetPassword(
|
||||
username,
|
||||
membershipProvider.RequiresQuestionAndAnswer ? passwordModel.Answer : null);
|
||||
|
||||
try
|
||||
{
|
||||
var result = membershipProvider.ChangePassword(username, oldPassword, passwordModel.NewPassword);
|
||||
return result == false
|
||||
? Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password", new[] { "value" }) })
|
||||
: Attempt.Succeed(new PasswordChangedModel());
|
||||
}
|
||||
catch (Exception ex1)
|
||||
{
|
||||
LogHelper.WarnWithException<WebSecurity>("Could not change member password", ex1);
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex1.Message + " (see log for full details)", new[] { "value" }) });
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
LogHelper.WarnWithException<WebSecurity>("Could not retrieve member password", ex2);
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex2.Message + " (see log for full details)", new[] { "value" }) });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Web.UI.WebControls;
|
||||
using System.Web.UI.WebControls.WebParts;
|
||||
using System.Web.UI.HtmlControls;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace umbraco.controls
|
||||
@@ -23,6 +24,23 @@ namespace umbraco.controls
|
||||
get { return Membership.Providers[MembershipProviderName]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether to show the old password field or not
|
||||
/// </summary>
|
||||
protected bool ShowOldPassword
|
||||
{
|
||||
get
|
||||
{
|
||||
var umbProvider = Provider as MembershipProviderBase;
|
||||
if (umbProvider != null && umbProvider.AllowManuallyChangingPassword)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Provider.EnablePasswordRetrieval == false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsChangingPassword
|
||||
{
|
||||
get
|
||||
|
||||
@@ -18,6 +18,30 @@ namespace umbraco.providers
|
||||
/// </summary>
|
||||
public class UsersMembershipProvider : MembershipProviderBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Override to maintain backwards compatibility with 0 required non-alphanumeric chars
|
||||
/// </summary>
|
||||
protected override int DefaultMinNonAlphanumericChars
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to maintain backwards compatibility with only 4 required length
|
||||
/// </summary>
|
||||
protected override int DefaultMinPasswordLength
|
||||
{
|
||||
get { return 4; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to maintain backwards compatibility
|
||||
/// </summary>
|
||||
protected override bool DefaultUseLegacyEncoding
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
|
||||
{
|
||||
if (config == null) throw new ArgumentNullException("config");
|
||||
@@ -41,8 +65,10 @@ namespace umbraco.providers
|
||||
/// During installation the application will not be configured, if this is the case and the 'default' password
|
||||
/// is stored in the database then we will validate the user - this will allow for an admin password reset if required
|
||||
/// </remarks>
|
||||
public override bool ChangePassword(string username, string oldPassword, string newPassword)
|
||||
protected override bool PerformChangePassword(string username, string oldPassword, string newPassword)
|
||||
{
|
||||
|
||||
|
||||
if (ApplicationContext.Current.IsConfigured == false && oldPassword == "default"
|
||||
|| ValidateUser(username, oldPassword))
|
||||
{
|
||||
|
||||
@@ -66,6 +66,38 @@ namespace umbraco.providers.members
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Override to maintain backwards compatibility with 0 required non-alphanumeric chars
|
||||
/// </summary>
|
||||
protected override int DefaultMinNonAlphanumericChars
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to maintain backwards compatibility with only 4 required length
|
||||
/// </summary>
|
||||
protected override int DefaultMinPasswordLength
|
||||
{
|
||||
get { return 4; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to maintain backwards compatibility
|
||||
/// </summary>
|
||||
protected override bool DefaultUseLegacyEncoding
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For backwards compatibility, this provider supports this option
|
||||
/// </summary>
|
||||
internal override bool AllowManuallyChangingPassword
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
#region Initialization Method
|
||||
/// <summary>
|
||||
@@ -148,16 +180,19 @@ namespace umbraco.providers.members
|
||||
/// Processes a request to update the password for a membership user.
|
||||
/// </summary>
|
||||
/// <param name="username">The user to update the password for.</param>
|
||||
/// <param name="oldPassword">The current password for the specified user.</param>
|
||||
/// <param name="oldPassword">This property is ignore for this provider</param>
|
||||
/// <param name="newPassword">The new password for the specified user.</param>
|
||||
/// <returns>
|
||||
/// true if the password was updated successfully; otherwise, false.
|
||||
/// </returns>
|
||||
public override bool ChangePassword(string username, string oldPassword, string newPassword)
|
||||
protected override bool PerformChangePassword(string username, string oldPassword, string newPassword)
|
||||
{
|
||||
|
||||
//NOTE: due to backwards compatibilty reasons, this provider doesn't care about the old password and
|
||||
// allows simply setting the password manually so we don't really care about the old password.
|
||||
// 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 = Member.GetMemberFromLoginNameAndPassword(username, oldPassword);
|
||||
var m = Member.GetMemberFromLoginName(username);
|
||||
if (m == null) return false;
|
||||
|
||||
var args = new ValidatePasswordEventArgs(username, newPassword, false);
|
||||
|
||||
Reference in New Issue
Block a user