Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/core-cannot-use-system-web
# Conflicts: # src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs # src/Umbraco.Tests/Testing/TestingTests/MockTests.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/BackOfficeUserManager.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
This commit is contained in:
@@ -43,7 +43,6 @@ namespace Umbraco.Web.Security
|
||||
IGlobalSettings globalSettings,
|
||||
// TODO: This could probably be optional?
|
||||
IPasswordConfiguration passwordConfiguration,
|
||||
IPasswordGenerator passwordGenerator,
|
||||
IIpResolver ipResolver)
|
||||
{
|
||||
if (services == null) throw new ArgumentNullException(nameof(services));
|
||||
@@ -59,7 +58,6 @@ namespace Umbraco.Web.Security
|
||||
contentSettings,
|
||||
globalSettings,
|
||||
passwordConfiguration,
|
||||
passwordGenerator,
|
||||
ipResolver));
|
||||
|
||||
app.SetBackOfficeUserManagerType<BackOfficeUserManager, BackOfficeIdentityUser>();
|
||||
@@ -85,7 +83,6 @@ namespace Umbraco.Web.Security
|
||||
BackOfficeUserStore customUserStore,
|
||||
// TODO: This could probably be optional?
|
||||
IPasswordConfiguration passwordConfiguration,
|
||||
IPasswordGenerator passwordGenerator,
|
||||
IIpResolver ipResolver)
|
||||
{
|
||||
if (runtimeState == null) throw new ArgumentNullException(nameof(runtimeState));
|
||||
@@ -98,7 +95,6 @@ namespace Umbraco.Web.Security
|
||||
customUserStore,
|
||||
contentSettings,
|
||||
passwordConfiguration,
|
||||
passwordGenerator,
|
||||
ipResolver));
|
||||
|
||||
app.SetBackOfficeUserManagerType<BackOfficeUserManager, BackOfficeIdentityUser>();
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin.Security.DataProtection;
|
||||
@@ -30,9 +28,8 @@ namespace Umbraco.Web.Security
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options,
|
||||
IContentSection contentSectionConfig,
|
||||
IPasswordConfiguration passwordConfiguration,
|
||||
IPasswordGenerator passwordGenerator,
|
||||
IIpResolver ipResolver)
|
||||
: base(store, passwordConfiguration, passwordGenerator, ipResolver)
|
||||
: base(store, passwordConfiguration, ipResolver)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException("options");
|
||||
InitUserManager(this, passwordConfiguration, options.DataProtectionProvider, contentSectionConfig);
|
||||
@@ -60,7 +57,6 @@ namespace Umbraco.Web.Security
|
||||
IContentSection contentSectionConfig,
|
||||
IGlobalSettings globalSettings,
|
||||
IPasswordConfiguration passwordConfiguration,
|
||||
IPasswordGenerator passwordGenerator,
|
||||
IIpResolver ipResolver)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException("options");
|
||||
@@ -68,7 +64,7 @@ namespace Umbraco.Web.Security
|
||||
if (externalLoginService == null) throw new ArgumentNullException("externalLoginService");
|
||||
|
||||
var store = new BackOfficeUserStore(userService, entityService, externalLoginService, globalSettings, mapper);
|
||||
var manager = new BackOfficeUserManager(store, options, contentSectionConfig, passwordConfiguration, passwordGenerator, ipResolver);
|
||||
var manager = new BackOfficeUserManager(store, options, contentSectionConfig, passwordConfiguration, ipResolver);
|
||||
return manager;
|
||||
}
|
||||
|
||||
@@ -85,10 +81,9 @@ namespace Umbraco.Web.Security
|
||||
BackOfficeUserStore customUserStore,
|
||||
IContentSection contentSectionConfig,
|
||||
IPasswordConfiguration passwordConfiguration,
|
||||
IPasswordGenerator passwordGenerator,
|
||||
IIpResolver ipResolver)
|
||||
{
|
||||
var manager = new BackOfficeUserManager(customUserStore, options, contentSectionConfig, passwordConfiguration, passwordGenerator, ipResolver);
|
||||
var manager = new BackOfficeUserManager(customUserStore, options, contentSectionConfig, passwordConfiguration, ipResolver);
|
||||
return manager;
|
||||
}
|
||||
#endregion
|
||||
@@ -102,14 +97,14 @@ namespace Umbraco.Web.Security
|
||||
public class BackOfficeUserManager<T> : UserManager<T, int>
|
||||
where T : BackOfficeIdentityUser
|
||||
{
|
||||
private PasswordGenerator _passwordGenerator;
|
||||
|
||||
public BackOfficeUserManager(IUserStore<T, int> store,
|
||||
IPasswordConfiguration passwordConfiguration,
|
||||
IPasswordGenerator passwordGenerator,
|
||||
IIpResolver ipResolver)
|
||||
: base(store)
|
||||
{
|
||||
PasswordConfiguration = passwordConfiguration;
|
||||
PasswordGenerator = passwordGenerator;
|
||||
IpResolver = ipResolver;
|
||||
}
|
||||
|
||||
@@ -150,24 +145,6 @@ namespace Umbraco.Web.Security
|
||||
return userIdentity;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Initializes the user manager with the correct options
|
||||
///// </summary>
|
||||
///// <param name="manager"></param>
|
||||
///// <param name="passwordConfig"></param>
|
||||
///// <param name="contentSectionConfig"></param>
|
||||
///// <param name="options"></param>
|
||||
///// <returns></returns>
|
||||
//protected void InitUserManager(
|
||||
// BackOfficeUserManager manager,
|
||||
// IPasswordConfiguration passwordConfig,
|
||||
// IContentSection contentSectionConfig,
|
||||
// IdentityFactoryOptions<BackOfficeUserManager> options)
|
||||
//{
|
||||
// //NOTE: This method is mostly here for backwards compat
|
||||
// base.InitUserManager(manager, passwordConfig, options.DataProtectionProvider, contentSectionConfig);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the user manager with the correct options
|
||||
/// </summary>
|
||||
@@ -265,7 +242,6 @@ namespace Umbraco.Web.Security
|
||||
/// </summary>
|
||||
public IBackOfficeUserPasswordChecker BackOfficeUserPasswordChecker { get; set; }
|
||||
public IPasswordConfiguration PasswordConfiguration { get; }
|
||||
public IPasswordGenerator PasswordGenerator { get; }
|
||||
public IIpResolver IpResolver { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -274,7 +250,8 @@ namespace Umbraco.Web.Security
|
||||
/// <returns></returns>
|
||||
public string GeneratePassword()
|
||||
{
|
||||
var password = PasswordGenerator.GeneratePassword(PasswordConfiguration);
|
||||
if (_passwordGenerator == null) _passwordGenerator = new PasswordGenerator(PasswordConfiguration);
|
||||
var password = _passwordGenerator.GeneratePassword();
|
||||
return password;
|
||||
}
|
||||
|
||||
@@ -348,8 +325,6 @@ namespace Umbraco.Web.Security
|
||||
public override Task<IdentityResult> ResetPasswordAsync(int userId, string token, string newPassword)
|
||||
{
|
||||
var result = base.ResetPasswordAsync(userId, token, newPassword);
|
||||
if (result.Result.Succeeded)
|
||||
RaisePasswordResetEvent(userId);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -585,12 +560,6 @@ namespace Umbraco.Web.Security
|
||||
OnPasswordChanged(new IdentityAuditEventArgs(AuditEvent.PasswordChanged, IpResolver.GetCurrentRequestIpAddress(), affectedUser: userId));
|
||||
}
|
||||
|
||||
// TODO: I don't think this is required anymore since from 7.7 we no longer display the reset password checkbox since that didn't make sense.
|
||||
internal void RaisePasswordResetEvent(int userId)
|
||||
{
|
||||
OnPasswordReset(new IdentityAuditEventArgs(AuditEvent.PasswordReset, IpResolver.GetCurrentRequestIpAddress(), affectedUser: userId));
|
||||
}
|
||||
|
||||
internal void RaiseResetAccessFailedCountEvent(int userId)
|
||||
{
|
||||
OnResetAccessFailedCount(new IdentityAuditEventArgs(AuditEvent.ResetAccessFailedCount, IpResolver.GetCurrentRequestIpAddress(), affectedUser: userId));
|
||||
|
||||
@@ -16,6 +16,7 @@ using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Editors;
|
||||
using Umbraco.Web.Security.Providers;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Umbraco.Web.Security
|
||||
{
|
||||
@@ -28,7 +29,6 @@ namespace Umbraco.Web.Security
|
||||
private readonly RoleProvider _roleProvider;
|
||||
private readonly IMemberService _memberService;
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IPublicAccessService _publicAccessService;
|
||||
private readonly AppCaches _appCaches;
|
||||
private readonly ILogger _logger;
|
||||
@@ -43,7 +43,6 @@ namespace Umbraco.Web.Security
|
||||
RoleProvider roleProvider,
|
||||
IMemberService memberService,
|
||||
IMemberTypeService memberTypeService,
|
||||
IUserService userService,
|
||||
IPublicAccessService publicAccessService,
|
||||
AppCaches appCaches,
|
||||
ILogger logger
|
||||
@@ -53,7 +52,6 @@ namespace Umbraco.Web.Security
|
||||
MemberCache = memberCache;
|
||||
_memberService = memberService;
|
||||
_memberTypeService = memberTypeService;
|
||||
_userService = userService;
|
||||
_publicAccessService = publicAccessService;
|
||||
_appCaches = appCaches;
|
||||
_logger = logger;
|
||||
@@ -645,8 +643,8 @@ namespace Umbraco.Web.Security
|
||||
/// <returns></returns>
|
||||
public virtual Attempt<PasswordChangedModel> ChangePassword(string username, ChangingPasswordModel passwordModel, MembershipProvider membershipProvider)
|
||||
{
|
||||
var passwordChanger = new PasswordChanger(_logger, _userService, HttpContext);
|
||||
return passwordChanger.ChangePasswordWithMembershipProvider(username, passwordModel, membershipProvider);
|
||||
var passwordChanger = new PasswordChanger(_logger);
|
||||
return ChangePasswordWithMembershipProvider(username, passwordModel, membershipProvider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -735,5 +733,63 @@ namespace Umbraco.Web.Security
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes password for a member/user given the membership provider and the password change model
|
||||
/// </summary>
|
||||
/// <param name="username">The username of the user having their password changed</param>
|
||||
/// <param name="passwordModel"></param>
|
||||
/// <param name="membershipProvider"></param>
|
||||
/// <returns></returns>
|
||||
private Attempt<PasswordChangedModel> ChangePasswordWithMembershipProvider(
|
||||
string username,
|
||||
ChangingPasswordModel passwordModel,
|
||||
MembershipProvider membershipProvider)
|
||||
{
|
||||
var umbracoBaseProvider = membershipProvider as MembershipProviderBase;
|
||||
|
||||
// YES! It is completely insane how many options you have to take into account based on the membership provider. yikes!
|
||||
|
||||
if (passwordModel == null) throw new ArgumentNullException(nameof(passwordModel));
|
||||
if (membershipProvider == null) throw new ArgumentNullException(nameof(membershipProvider));
|
||||
var userId = -1;
|
||||
|
||||
|
||||
//we're not resetting it so we need to try to change it.
|
||||
|
||||
if (passwordModel.NewPassword.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Cannot set an empty password", new[] { "value" }) });
|
||||
}
|
||||
|
||||
if (membershipProvider.EnablePasswordRetrieval)
|
||||
{
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Membership providers using encrypted passwords and password retrieval are not supported", new[] { "value" }) });
|
||||
}
|
||||
|
||||
//without being able to retrieve the original password
|
||||
if (passwordModel.OldPassword.IsNullOrWhiteSpace())
|
||||
{
|
||||
//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[] { "oldPassword" }) });
|
||||
}
|
||||
|
||||
//if an old password is supplied 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[] { "oldPassword" }) })
|
||||
: Attempt.Succeed(new PasswordChangedModel());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn<PasswordChanger>(ex, "Could not change member password");
|
||||
return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Could not change password, error: " + ex.Message + " (see log for full details)", new[] { "value" }) });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,16 +52,6 @@ namespace Umbraco.Web.Security
|
||||
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>
|
||||
public virtual bool AllowManuallyChangingPassword
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the raw password value for a given user
|
||||
/// </summary>
|
||||
@@ -307,24 +297,10 @@ namespace Umbraco.Web.Security
|
||||
/// <returns>
|
||||
/// true if the password was updated successfully; otherwise, false.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Checks to ensure the AllowManuallyChangingPassword rule is adhered to
|
||||
/// </remarks>
|
||||
public override bool ChangePassword(string username, string oldPassword, string newPassword)
|
||||
{
|
||||
string rawPasswordValue = string.Empty;
|
||||
if (oldPassword.IsNullOrWhiteSpace() && AllowManuallyChangingPassword == false)
|
||||
{
|
||||
//we need to lookup the member since this could be a brand new member without a password set
|
||||
var rawPassword = GetRawPassword(username);
|
||||
rawPasswordValue = rawPassword.Success ? rawPassword.Result : string.Empty;
|
||||
if (rawPassword.Success == false || rawPasswordValue.StartsWith(Constants.Security.EmptyPasswordPrefix) == 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var args = new ValidatePasswordEventArgs(username, newPassword, false);
|
||||
OnValidatingPassword(args);
|
||||
|
||||
@@ -339,14 +315,13 @@ namespace Umbraco.Web.Security
|
||||
// * the member is new and doesn't have a password set
|
||||
// * during installation to set the admin password
|
||||
var installing = Current.RuntimeState.Level == RuntimeLevel.Install;
|
||||
if (AllowManuallyChangingPassword == false
|
||||
&& (rawPasswordValue.StartsWith(Constants.Security.EmptyPasswordPrefix)
|
||||
|| (installing && oldPassword == "default")))
|
||||
if (rawPasswordValue.StartsWith(Constants.Security.EmptyPasswordPrefix)
|
||||
|| (installing && oldPassword == "default"))
|
||||
{
|
||||
return PerformChangePassword(username, oldPassword, newPassword);
|
||||
}
|
||||
|
||||
if (AllowManuallyChangingPassword == false)
|
||||
if (!oldPassword.IsNullOrWhiteSpace())
|
||||
{
|
||||
if (ValidateUser(username, oldPassword) == false) return false;
|
||||
}
|
||||
@@ -385,7 +360,7 @@ namespace Umbraco.Web.Security
|
||||
throw new NotSupportedException("Updating the password Question and Answer is not available if requiresQuestionAndAnswer is not set in web.config");
|
||||
}
|
||||
|
||||
if (AllowManuallyChangingPassword == false)
|
||||
if (!password.IsNullOrWhiteSpace())
|
||||
{
|
||||
if (ValidateUser(username, password) == false)
|
||||
{
|
||||
|
||||
@@ -23,40 +23,6 @@ namespace Umbraco.Web.Security
|
||||
return membershipMember;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method to check if a password can be reset based on a given provider and the current request (logged in user)
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="userService"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// An Admin can always reset the password
|
||||
/// </remarks>
|
||||
internal static bool CanResetPassword(this MembershipProvider provider, IUserService userService)
|
||||
{
|
||||
if (provider == null) throw new ArgumentNullException("provider");
|
||||
|
||||
var canReset = provider.EnablePasswordReset;
|
||||
|
||||
if (userService == null) return canReset;
|
||||
|
||||
//we need to check for the special case in which a user is an admin - in which case they can reset the password even if EnablePasswordReset == false
|
||||
if (provider.EnablePasswordReset == false)
|
||||
{
|
||||
var identity = Thread.CurrentPrincipal.GetUmbracoIdentity();
|
||||
if (identity != null)
|
||||
{
|
||||
var user = userService.GetUserById(identity.Id.TryConvertTo<int>().Result);
|
||||
if (user == null) throw new InvalidOperationException("No user with username " + identity.Username + " found");
|
||||
var userIsAdmin = user.IsAdmin();
|
||||
if (userIsAdmin)
|
||||
{
|
||||
canReset = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return canReset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to get the Umbraco Members membership provider based on its alias
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Web.Security.Providers
|
||||
/// <summary>
|
||||
/// Custom Membership Provider for Umbraco Members (User authentication for Frontend applications NOT umbraco CMS)
|
||||
/// </summary>
|
||||
public class MembersMembershipProvider : UmbracoMembershipProvider<IMembershipMemberService, IMember>, IUmbracoMemberTypeMembershipProvider
|
||||
public class MembersMembershipProvider : UmbracoMembershipProvider<IMembershipMemberService, IMember>
|
||||
{
|
||||
public MembersMembershipProvider()
|
||||
: this(Current.Services.MemberService, Current.Services.MemberTypeService, Current.UmbracoVersion, Current.HostingEnvironment, Current.IpResolver)
|
||||
|
||||
@@ -44,16 +44,6 @@ namespace Umbraco.Web.Security.Providers
|
||||
|
||||
protected abstract MembershipUser ConvertToMembershipUser(TEntity entity);
|
||||
|
||||
private bool _allowManuallyChangingPassword = false;
|
||||
|
||||
/// <summary>
|
||||
/// For backwards compatibility, this provider supports this option by default it is false
|
||||
/// </summary>
|
||||
public override bool AllowManuallyChangingPassword
|
||||
{
|
||||
get { return _allowManuallyChangingPassword; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the provider.
|
||||
/// </summary>
|
||||
@@ -72,8 +62,6 @@ namespace Umbraco.Web.Security.Providers
|
||||
|
||||
// Initialize base provider class
|
||||
base.Initialize(name, config);
|
||||
|
||||
_allowManuallyChangingPassword = config.GetValue("allowManuallyChangingPassword", false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -531,7 +519,7 @@ namespace Umbraco.Web.Security.Providers
|
||||
};
|
||||
}
|
||||
|
||||
var authenticated = PasswordSecurity.CheckPassword(password, member.RawPasswordValue);
|
||||
var authenticated = PasswordSecurity.VerifyPassword(password, member.RawPasswordValue);
|
||||
|
||||
if (authenticated == false)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user