diff --git a/src/Microsoft.AspNet.Identity/UserOptions.cs b/src/Microsoft.AspNet.Identity/UserOptions.cs index 5b2578aa3b..214d7f9e1e 100644 --- a/src/Microsoft.AspNet.Identity/UserOptions.cs +++ b/src/Microsoft.AspNet.Identity/UserOptions.cs @@ -1,20 +1,18 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Text.RegularExpressions; + namespace Microsoft.AspNet.Identity { public class UserOptions { public UserOptions() { - AllowOnlyAlphanumericNames = true; //User.RequireUniqueEmail = true; // TODO: app decision? } - /// - /// Only allow [A-Za-z0-9@_] in UserNames - /// - public bool AllowOnlyAlphanumericNames { get; set; } + public string UserNameValidationRegex { get; set; } = "^[a-zA-Z0-9@_\\.]+$"; /// /// If set, enforces that emails are non empty, valid, and unique diff --git a/src/Microsoft.AspNet.Identity/UserValidator.cs b/src/Microsoft.AspNet.Identity/UserValidator.cs index 2fea50531d..749f3a9f3f 100644 --- a/src/Microsoft.AspNet.Identity/UserValidator.cs +++ b/src/Microsoft.AspNet.Identity/UserValidator.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; #if ASPNET50 using System.Net.Mail; #endif +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -46,48 +46,6 @@ namespace Microsoft.AspNet.Identity return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success; } - // TODO: Revisit extensibility for Validators - - /// - /// Returns true if the character is a digit between '0' and '9' - /// - /// - /// - public virtual bool IsDigit(char c) - { - return c >= '0' && c <= '9'; - } - - /// - /// Returns true if the character is between 'a' and 'z' - /// - /// - /// - public virtual bool IsLower(char c) - { - return c >= 'a' && c <= 'z'; - } - - /// - /// Returns true if the character is between 'A' and 'Z' - /// - /// - /// - public virtual bool IsUpper(char c) - { - return c >= 'A' && c <= 'Z'; - } - - /// - /// Returns true if the character is upper, lower, a digit, or a common email character [@_.] - /// - /// - /// - public virtual bool IsAlphaNumeric(char c) - { - return IsUpper(c) || IsLower(c) || IsDigit(c) || c == '@' || c == '_' || c == '.'; - } - private async Task ValidateUserName(UserManager manager, TUser user, ICollection errors) { var userName = await manager.GetUserNameAsync(user); @@ -95,9 +53,8 @@ namespace Microsoft.AspNet.Identity { errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "UserName")); } - else if (manager.Options.User.AllowOnlyAlphanumericNames && !userName.All(IsAlphaNumeric)) + else if (manager.Options.User.UserNameValidationRegex != null && !Regex.IsMatch(userName, manager.Options.User.UserNameValidationRegex)) { - // If any characters are not letters or digits, its an illegal user name errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.InvalidUserName, userName)); } else diff --git a/src/Microsoft.AspNet.Identity/project.json b/src/Microsoft.AspNet.Identity/project.json index 6c44cd8eac..68b759996b 100644 --- a/src/Microsoft.AspNet.Identity/project.json +++ b/src/Microsoft.AspNet.Identity/project.json @@ -34,6 +34,7 @@ "System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0", "System.Text.Encoding": "4.0.10.0", "System.Text.Encoding.Extensions": "4.0.10.0", + "System.Text.RegularExpressions": "4.0.0.0", "System.Threading.Tasks": "4.0.10.0" } } diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs index 3eb8ea1aa5..d72a7cc5ff 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Identity.InMemory.Test options.Password.RequireLowercase = false; options.Password.RequireNonLetterOrDigit = false; options.Password.RequireUppercase = false; - options.User.AllowOnlyAlphanumericNames = false; + options.User.UserNameValidationRegex = null; }); return services.BuildServiceProvider().GetService>(); } diff --git a/test/Microsoft.AspNet.Identity.SqlServer.InMemory.Test/InMemoryEFUserStoreTest.cs b/test/Microsoft.AspNet.Identity.SqlServer.InMemory.Test/InMemoryEFUserStoreTest.cs index 70e3d9eaf6..ef93470e05 100644 --- a/test/Microsoft.AspNet.Identity.SqlServer.InMemory.Test/InMemoryEFUserStoreTest.cs +++ b/test/Microsoft.AspNet.Identity.SqlServer.InMemory.Test/InMemoryEFUserStoreTest.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.InMemory.Test options.Password.RequireLowercase = false; options.Password.RequireNonLetterOrDigit = false; options.Password.RequireUppercase = false; - options.User.AllowOnlyAlphanumericNames = false; + options.User.UserNameValidationRegex = null; }); return services.BuildServiceProvider().GetService>(); } diff --git a/test/Microsoft.AspNet.Identity.SqlServer.Test/SqlStoreTestBase.cs b/test/Microsoft.AspNet.Identity.SqlServer.Test/SqlStoreTestBase.cs index 050c37a069..cdab3b7037 100644 --- a/test/Microsoft.AspNet.Identity.SqlServer.Test/SqlStoreTestBase.cs +++ b/test/Microsoft.AspNet.Identity.SqlServer.Test/SqlStoreTestBase.cs @@ -146,7 +146,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test options.Password.RequireNonLetterOrDigit = false; options.Password.RequireUppercase = false; options.Password.RequireDigit = false; - options.User.AllowOnlyAlphanumericNames = false; + options.User.UserNameValidationRegex = null; }); services.SetupOptions(options => options.UseSqlServer(ConnectionString)); diff --git a/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs b/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs index 960ed8fbac..3c6b9d66b2 100644 --- a/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Identity.Test Assert.True(options.Password.RequireUppercase); Assert.Equal(6, options.Password.RequiredLength); - Assert.True(options.User.AllowOnlyAlphanumericNames); + Assert.Equal("^[a-zA-Z0-9@_\\.]+$", options.User.UserNameValidationRegex); Assert.False(options.User.RequireUniqueEmail); Assert.Equal(ClaimTypes.Role, options.ClaimsIdentity.RoleClaimType); @@ -77,8 +77,7 @@ namespace Microsoft.AspNet.Identity.Test Assert.Equal(usernameClaimType, options.ClaimsIdentity.UserNameClaimType); Assert.Equal(securityStampClaimType, options.ClaimsIdentity.SecurityStampClaimType); Assert.True(options.User.RequireUniqueEmail); - Assert.True(options.User.AllowOnlyAlphanumericNames); - Assert.True(options.User.AllowOnlyAlphanumericNames); + Assert.Equal("^[a-zA-Z0-9@_\\.]+$", options.User.UserNameValidationRegex); Assert.False(options.Password.RequireDigit); Assert.False(options.Password.RequireLowercase); Assert.False(options.Password.RequireNonLetterOrDigit); diff --git a/test/Microsoft.AspNet.Identity.Test/UserValidatorTest.cs b/test/Microsoft.AspNet.Identity.Test/UserValidatorTest.cs index a79b8bbf31..793dd36598 100644 --- a/test/Microsoft.AspNet.Identity.Test/UserValidatorTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/UserValidatorTest.cs @@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Identity.Test { // Setup var manager = MockHelpers.TestUserManager(new NoopUserStore()); - manager.Options.User.AllowOnlyAlphanumericNames = false; + manager.Options.User.UserNameValidationRegex = null; var validator = new UserValidator(); var user = new TestUser {UserName = userName}; diff --git a/test/Shared/MockHelpers.cs b/test/Shared/MockHelpers.cs index c7b09dcc50..89825915c3 100644 --- a/test/Shared/MockHelpers.cs +++ b/test/Shared/MockHelpers.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Identity.Test options.Password.RequireLowercase = false; options.Password.RequireNonLetterOrDigit = false; options.Password.RequireUppercase = false; - options.User.AllowOnlyAlphanumericNames = false; + options.User.UserNameValidationRegex = null; }); return services.BuildServiceProvider().GetService>(); } diff --git a/test/Shared/UserManagerTestBase.cs b/test/Shared/UserManagerTestBase.cs index ab2b45a68e..44e34c0eeb 100644 --- a/test/Shared/UserManagerTestBase.cs +++ b/test/Shared/UserManagerTestBase.cs @@ -392,7 +392,7 @@ namespace Microsoft.AspNet.Identity.Test { var manager = CreateManager(); manager.Options.User.UseUserNameAsEmail = true; - manager.Options.User.AllowOnlyAlphanumericNames = false; + manager.Options.User.UserNameValidationRegex = null; var user = CreateTestUser(); var email = user.UserName + "@test.com"; user.UserName = email;