From e98084fdf60e4957320b8791a78b0c30bfd863f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 6 Aug 2020 16:30:51 +0300 Subject: [PATCH] Refactor: Extract class RandomPasswordGenerator --- .../Pages/Account/Register.cshtml.cs | 47 +---------- .../Abp/Identity/RandomPasswordGenerator.cs | 84 +++++++++++++++++++ .../IdentityClaimTypeManager_Tests.cs | 2 - .../Identity/RandomPasswordGenerator_Tests.cs | 23 +++++ 4 files changed, 111 insertions(+), 45 deletions(-) create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/RandomPasswordGenerator.cs create mode 100644 modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RandomPasswordGenerator_Tests.cs diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs index 6baefc6745..d6b7a862cf 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs @@ -19,6 +19,7 @@ namespace Volo.Abp.Account.Web.Pages.Account public class RegisterModel : AccountPageModel { protected IAccountAppService AccountAppService { get; } + protected RandomPasswordGenerator RandomPasswordGenerator { get; } [BindProperty(SupportsGet = true)] public string ReturnUrl { get; set; } @@ -35,9 +36,10 @@ namespace Volo.Abp.Account.Web.Pages.Account [BindProperty(SupportsGet = true)] public string ExternalLoginAuthSchema { get; set; } - public RegisterModel(IAccountAppService accountAppService) + public RegisterModel(IAccountAppService accountAppService, RandomPasswordGenerator randomPasswordGenerator) { AccountAppService = accountAppService; + RandomPasswordGenerator = randomPasswordGenerator; } public virtual async Task OnGetAsync() @@ -94,7 +96,7 @@ namespace Volo.Abp.Account.Web.Pages.Account registerDto.EmailAddress = Input.EmailAddress; registerDto.UserName = Input.EmailAddress; - registerDto.Password = GeneratePassword(); + registerDto.Password = await RandomPasswordGenerator.CreateAsync(); } else { @@ -137,47 +139,6 @@ namespace Volo.Abp.Account.Web.Pages.Account } } - protected virtual string GeneratePassword() - { - var random = new Random(); - var options = UserManager.Options.Password; - int length = random.Next(options.RequiredLength, IdentityUserConsts.MaxPasswordLength - 1); - - bool nonAlphanumeric = options.RequireNonAlphanumeric; - bool digit = options.RequireDigit; - bool lowercase = options.RequireLowercase; - bool uppercase = options.RequireUppercase; - - StringBuilder password = new StringBuilder(); - - while (password.Length < length) - { - char c = (char)random.Next(32, 126); - - password.Append(c); - - if (char.IsDigit(c)) - digit = false; - else if (char.IsLower(c)) - lowercase = false; - else if (char.IsUpper(c)) - uppercase = false; - else if (!char.IsLetterOrDigit(c)) - nonAlphanumeric = false; - } - - if (nonAlphanumeric) - password.Append((char)random.Next(33, 48)); - if (digit) - password.Append((char)random.Next(48, 58)); - if (lowercase) - password.Append((char)random.Next(97, 123)); - if (uppercase) - password.Append((char)random.Next(65, 91)); - - return password.ToString(); - } - protected virtual async Task CheckSelfRegistrationAsync() { if (!await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled) || diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/RandomPasswordGenerator.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/RandomPasswordGenerator.cs new file mode 100644 index 0000000000..40643d8a76 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/RandomPasswordGenerator.cs @@ -0,0 +1,84 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Identity +{ + /// + /// This class can be used to generate random password + /// based on the rules defined in the . + /// + public class RandomPasswordGenerator : ITransientDependency + { + public const int MinPasswordLength = 32; + + protected IdentityOptions Options { get; } + protected Random Random { get; } + + public RandomPasswordGenerator(IOptions options) + { + Options = options.Value; + Random = new Random(); + } + + public virtual Task CreateAsync() + { + var nonAlphanumeric = Options.Password.RequireNonAlphanumeric; + var digit = Options.Password.RequireDigit; + var lowercase = Options.Password.RequireLowercase; + var uppercase = Options.Password.RequireUppercase; + + var passwordBuilder = new StringBuilder(); + + var length = Math.Max(Options.Password.RequiredLength, MinPasswordLength); + while (passwordBuilder.Length < length) + { + var nextChar = (char)Random.Next(32, 126); + + passwordBuilder.Append(nextChar); + + if (char.IsDigit(nextChar)) + { + digit = false; + } + else if (char.IsLower(nextChar)) + { + lowercase = false; + } + else if (char.IsUpper(nextChar)) + { + uppercase = false; + } + else if (!char.IsLetterOrDigit(nextChar)) + { + nonAlphanumeric = false; + } + } + + if (nonAlphanumeric) + { + passwordBuilder.Append((char)Random.Next(33, 48)); + } + + if (digit) + { + passwordBuilder.Append((char)Random.Next(48, 58)); + } + + if (lowercase) + { + passwordBuilder.Append((char)Random.Next(97, 123)); + } + + if (uppercase) + { + passwordBuilder.Append((char)Random.Next(65, 91)); + } + + return Task.FromResult(passwordBuilder.ToString()); + } + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityClaimTypeManager_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityClaimTypeManager_Tests.cs index c5c68d40c6..1ef603e6b3 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityClaimTypeManager_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityClaimTypeManager_Tests.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; using Shouldly; using Xunit; diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RandomPasswordGenerator_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RandomPasswordGenerator_Tests.cs new file mode 100644 index 0000000000..f28fed08d8 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RandomPasswordGenerator_Tests.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace Volo.Abp.Identity +{ + public class RandomPasswordGenerator_Tests : AbpIdentityDomainTestBase + { + private readonly RandomPasswordGenerator _randomPasswordGenerator; + + public RandomPasswordGenerator_Tests() + { + _randomPasswordGenerator = GetRequiredService(); + } + + [Fact] + public async Task CreateAsync() + { + var password = await _randomPasswordGenerator.CreateAsync(); + password.Length.ShouldBeGreaterThanOrEqualTo(RandomPasswordGenerator.MinPasswordLength); + } + } +}