Create user now generates a password
This commit is contained in:
@@ -90,6 +90,7 @@ namespace Umbraco.Core.Security
|
||||
base.InitUserManager(manager, membershipProvider, options.DataProtectionProvider);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -152,15 +153,8 @@ namespace Umbraco.Core.Security
|
||||
};
|
||||
|
||||
// Configure validation logic for passwords
|
||||
manager.PasswordValidator = new PasswordValidator
|
||||
{
|
||||
RequiredLength = membershipProvider.MinRequiredPasswordLength,
|
||||
RequireNonLetterOrDigit = membershipProvider.MinRequiredNonAlphanumericCharacters > 0,
|
||||
RequireDigit = false,
|
||||
RequireLowercase = false,
|
||||
RequireUppercase = false
|
||||
//TODO: Do we support the old regex match thing that membership providers used?
|
||||
};
|
||||
var provider = MembershipProviderExtensions.GetUsersMembershipProvider();
|
||||
manager.PasswordValidator = new MembershipProviderPasswordValidator(provider);
|
||||
|
||||
//use a custom hasher based on our membership provider
|
||||
manager.PasswordHasher = new MembershipPasswordHasher(membershipProvider);
|
||||
@@ -238,5 +232,39 @@ namespace Umbraco.Core.Security
|
||||
/// Gets/sets the default back office user password checker
|
||||
/// </summary>
|
||||
public IBackOfficeUserPasswordChecker BackOfficeUserPasswordChecker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to generate a password for a user based on the current password validator
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GeneratePassword()
|
||||
{
|
||||
var passwordValidator = PasswordValidator as PasswordValidator;
|
||||
if (passwordValidator != null)
|
||||
{
|
||||
var password = Membership.GeneratePassword(
|
||||
passwordValidator.RequiredLength,
|
||||
passwordValidator.RequireNonLetterOrDigit ? 2 : 0);
|
||||
|
||||
var random = new Random();
|
||||
|
||||
var passwordChars = password.ToCharArray();
|
||||
|
||||
if (passwordValidator.RequireDigit && passwordChars.ContainsAny(Enumerable.Range(48, 58).Select(x => (char)x)))
|
||||
password += Convert.ToChar(random.Next(48, 58)); // 0-9
|
||||
|
||||
if (passwordValidator.RequireLowercase && passwordChars.ContainsAny(Enumerable.Range(97, 123).Select(x => (char)x)))
|
||||
password += Convert.ToChar(random.Next(97, 123)); // a-z
|
||||
|
||||
if (passwordValidator.RequireUppercase && passwordChars.ContainsAny(Enumerable.Range(65, 91).Select(x => (char)x)))
|
||||
password += Convert.ToChar(random.Next(65, 91)); // A-Z
|
||||
|
||||
if (passwordValidator.RequireNonLetterOrDigit && passwordChars.ContainsAny(Enumerable.Range(33, 48).Select(x => (char)x)))
|
||||
password += Convert.ToChar(random.Next(33, 48)); // symbols !"#$%&'()*+,-./
|
||||
|
||||
return password;
|
||||
}
|
||||
throw new NotSupportedException("Cannot generate a password since the type of the password validator (" + PasswordValidator.GetType() + ") is not known");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensure that both the normal password validator rules are processed along with the underlying memberhsip provider rules
|
||||
/// </summary>
|
||||
public class MembershipProviderPasswordValidator : PasswordValidator
|
||||
{
|
||||
public MembershipProvider Provider { get; private set; }
|
||||
|
||||
public MembershipProviderPasswordValidator(MembershipProvider provider)
|
||||
{
|
||||
Provider = provider;
|
||||
|
||||
RequiredLength = Provider.MinRequiredPasswordLength;
|
||||
RequireNonLetterOrDigit = Provider.MinRequiredNonAlphanumericCharacters > 0;
|
||||
RequireDigit = false;
|
||||
RequireLowercase = false;
|
||||
RequireUppercase = false;
|
||||
}
|
||||
|
||||
public override async Task<IdentityResult> ValidateAsync(string item)
|
||||
{
|
||||
var result = await base.ValidateAsync(item);
|
||||
if (result.Succeeded == false)
|
||||
return result;
|
||||
var providerValidate = MembershipProviderBase.IsPasswordValid(item, Provider.MinRequiredNonAlphanumericCharacters, Provider.PasswordStrengthRegularExpression, Provider.MinRequiredPasswordLength);
|
||||
if (providerValidate.Success == false)
|
||||
{
|
||||
return IdentityResult.Failed("Could not set password, password rules violated: " + providerValidate.Result);
|
||||
}
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -654,6 +654,7 @@
|
||||
<Compile Include="Security\IBackOfficeUserPasswordChecker.cs" />
|
||||
<Compile Include="Security\MembershipPasswordHasher.cs" />
|
||||
<Compile Include="Security\EmailService.cs" />
|
||||
<Compile Include="Security\MembershipProviderPasswordValidator.cs" />
|
||||
<Compile Include="Security\OwinExtensions.cs" />
|
||||
<Compile Include="SemVersionExtensions.cs" />
|
||||
<Compile Include="Serialization\NoTypeConverterJsonConverter.cs" />
|
||||
|
||||
@@ -234,8 +234,10 @@ namespace Umbraco.Web.Editors
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
emptyContent = new Member(contentType);
|
||||
emptyContent.AdditionalData["NewPassword"] = Membership.GeneratePassword(Membership.MinRequiredPasswordLength, Membership.MinRequiredNonAlphanumericCharacters);
|
||||
emptyContent.AdditionalData["NewPassword"] = Membership.GeneratePassword(provider.MinRequiredPasswordLength, provider.MinRequiredNonAlphanumericCharacters);
|
||||
return Mapper.Map<IMember, MemberDisplay>(emptyContent);
|
||||
case MembershipScenario.CustomProviderWithUmbracoLink:
|
||||
//TODO: Support editing custom properties for members with a custom membership provider here.
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using System.Web.Security;
|
||||
using System.Web.WebPages;
|
||||
using AutoMapper;
|
||||
using ClientDependency.Core;
|
||||
@@ -203,6 +204,7 @@ namespace Umbraco.Web.Editors
|
||||
string orderBy = "username",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
[FromUri]string[] userGroups = null,
|
||||
//TODO: Add User state filtering
|
||||
string filter = "")
|
||||
{
|
||||
long pageIndex = pageNumber - 1;
|
||||
@@ -246,18 +248,36 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
//we want to create the user with the UserManager, this ensures the 'empty' (special) password
|
||||
//format is applied without us having to duplicate that logic
|
||||
var created = await UserManager.CreateAsync(new BackOfficeIdentityUser
|
||||
var identityUser = new BackOfficeIdentityUser
|
||||
{
|
||||
Email = userSave.Email,
|
||||
Name = userSave.Name,
|
||||
UserName = userSave.Email
|
||||
});
|
||||
};
|
||||
var created = await UserManager.CreateAsync(identityUser);
|
||||
if (created.Succeeded == false)
|
||||
{
|
||||
throw new HttpResponseException(
|
||||
Request.CreateNotificationValidationErrorResponse(string.Join(", ", created.Errors)));
|
||||
}
|
||||
|
||||
//we need to generate a password, however we can only do that if the user manager has a password validator that
|
||||
//we can read values from
|
||||
var passwordValidator = UserManager.PasswordValidator as PasswordValidator;
|
||||
var resetPassword = string.Empty;
|
||||
if (passwordValidator != null)
|
||||
{
|
||||
var password = UserManager.GeneratePassword();
|
||||
|
||||
var result = await UserManager.AddPasswordAsync(identityUser.Id, password);
|
||||
if (result.Succeeded == false)
|
||||
{
|
||||
throw new HttpResponseException(
|
||||
Request.CreateNotificationValidationErrorResponse(string.Join(", ", created.Errors)));
|
||||
}
|
||||
resetPassword = password;
|
||||
}
|
||||
|
||||
//now re-look the user back up which will now exist
|
||||
var user = Services.UserService.GetByEmail(userSave.Email);
|
||||
|
||||
@@ -269,7 +289,9 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
Services.UserService.Save(user);
|
||||
|
||||
return Mapper.Map<UserDisplay>(user);
|
||||
var display = Mapper.Map<UserDisplay>(user);
|
||||
display.ResetPasswordValue = resetPassword;
|
||||
return display;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user