Split ILookupNormalizer.Normalize into Name/Email methods (#8412)
This commit is contained in:
parent
22623b905f
commit
95ab2fa4af
|
|
@ -109,7 +109,8 @@ namespace Microsoft.AspNetCore.Identity
|
|||
}
|
||||
public partial interface ILookupNormalizer
|
||||
{
|
||||
string Normalize(string key);
|
||||
string NormalizeEmail(string email);
|
||||
string NormalizeName(string name);
|
||||
}
|
||||
public partial interface ILookupProtector
|
||||
{
|
||||
|
|
@ -450,10 +451,11 @@ namespace Microsoft.AspNetCore.Identity
|
|||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
public virtual System.Threading.Tasks.Task<bool> ValidateAsync(string purpose, string token, Microsoft.AspNetCore.Identity.UserManager<TUser> manager, TUser user) { throw null; }
|
||||
}
|
||||
public partial class UpperInvariantLookupNormalizer : Microsoft.AspNetCore.Identity.ILookupNormalizer
|
||||
public sealed partial class UpperInvariantLookupNormalizer : Microsoft.AspNetCore.Identity.ILookupNormalizer
|
||||
{
|
||||
public UpperInvariantLookupNormalizer() { }
|
||||
public virtual string Normalize(string key) { throw null; }
|
||||
public string NormalizeEmail(string email) { throw null; }
|
||||
public string NormalizeName(string name) { throw null; }
|
||||
}
|
||||
public partial class UserClaimsPrincipalFactory<TUser> : Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<TUser> where TUser : class
|
||||
{
|
||||
|
|
@ -600,7 +602,8 @@ namespace Microsoft.AspNetCore.Identity
|
|||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
public virtual System.Threading.Tasks.Task<bool> IsLockedOutAsync(TUser user) { throw null; }
|
||||
public virtual System.Threading.Tasks.Task<bool> IsPhoneNumberConfirmedAsync(TUser user) { throw null; }
|
||||
public virtual string NormalizeKey(string key) { throw null; }
|
||||
public virtual string NormalizeEmail(string email) { throw null; }
|
||||
public virtual string NormalizeName(string name) { throw null; }
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Identity.IdentityResult> RedeemTwoFactorRecoveryCodeAsync(TUser user, string code) { throw null; }
|
||||
public virtual void RegisterTokenProvider(string providerName, Microsoft.AspNetCore.Identity.IUserTwoFactorTokenProvider<TUser> provider) { }
|
||||
|
|
|
|||
|
|
@ -4,15 +4,23 @@
|
|||
namespace Microsoft.AspNetCore.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an abstraction for normalizing keys for lookup purposes.
|
||||
/// Provides an abstraction for normalizing keys (emails/names) for lookup purposes.
|
||||
/// </summary>
|
||||
public interface ILookupNormalizer
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a normalized representation of the specified <paramref name="key"/>.
|
||||
/// Returns a normalized representation of the specified <paramref name="name"/>.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to normalize.</param>
|
||||
/// <returns>A normalized representation of the specified <paramref name="key"/>.</returns>
|
||||
string Normalize(string key);
|
||||
/// <param name="name">The key to normalize.</param>
|
||||
/// <returns>A normalized representation of the specified <paramref name="name"/>.</returns>
|
||||
string NormalizeName(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized representation of the specified <paramref name="email"/>.
|
||||
/// </summary>
|
||||
/// <param name="email">The email to normalize.</param>
|
||||
/// <returns>A normalized representation of the specified <paramref name="email"/>.</returns>
|
||||
string NormalizeEmail(string email);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
/// <returns>A normalized representation of the specified <paramref name="key"/>.</returns>
|
||||
public virtual string NormalizeKey(string key)
|
||||
{
|
||||
return (KeyNormalizer == null) ? key : KeyNormalizer.Normalize(key);
|
||||
return (KeyNormalizer == null) ? key : KeyNormalizer.NormalizeName(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -6,21 +6,27 @@ namespace Microsoft.AspNetCore.Identity
|
|||
/// <summary>
|
||||
/// Implements <see cref="ILookupNormalizer"/> by converting keys to their upper cased invariant culture representation.
|
||||
/// </summary>
|
||||
public class UpperInvariantLookupNormalizer : ILookupNormalizer
|
||||
public sealed class UpperInvariantLookupNormalizer : ILookupNormalizer
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a normalized representation of the specified <paramref name="key"/>
|
||||
/// by converting keys to their upper cased invariant culture representation.
|
||||
/// Returns a normalized representation of the specified <paramref name="name"/>.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to normalize.</param>
|
||||
/// <returns>A normalized representation of the specified <paramref name="key"/>.</returns>
|
||||
public virtual string Normalize(string key)
|
||||
/// <param name="name">The key to normalize.</param>
|
||||
/// <returns>A normalized representation of the specified <paramref name="name"/>.</returns>
|
||||
public string NormalizeName(string name)
|
||||
{
|
||||
if (key == null)
|
||||
if (name == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return key.Normalize().ToUpperInvariant();
|
||||
return name.Normalize().ToUpperInvariant();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a normalized representation of the specified <paramref name="email"/>.
|
||||
/// </summary>
|
||||
/// <param name="email">The email to normalize.</param>
|
||||
/// <returns>A normalized representation of the specified <paramref name="email"/>.</returns>
|
||||
public string NormalizeEmail(string email) => NormalizeName(email);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,15 +105,15 @@ namespace Microsoft.AspNetCore.Identity
|
|||
foreach (var providerName in Options.Tokens.ProviderMap.Keys)
|
||||
{
|
||||
var description = Options.Tokens.ProviderMap[providerName];
|
||||
|
||||
var provider = (description.ProviderInstance ?? services.GetRequiredService(description.ProviderType))
|
||||
|
||||
var provider = (description.ProviderInstance ?? services.GetRequiredService(description.ProviderType))
|
||||
as IUserTwoFactorTokenProvider<TUser>;
|
||||
if (provider != null)
|
||||
{
|
||||
RegisterTokenProvider(providerName, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Options.Stores.ProtectPersonalData)
|
||||
{
|
||||
|
|
@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
/// The <see cref="ILookupNormalizer"/> used to normalize things like user and role names.
|
||||
/// </summary>
|
||||
public ILookupNormalizer KeyNormalizer { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IdentityErrorDescriber"/> used to generate error messages.
|
||||
/// </summary>
|
||||
|
|
@ -547,7 +547,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
{
|
||||
throw new ArgumentNullException(nameof(userName));
|
||||
}
|
||||
userName = NormalizeKey(userName);
|
||||
userName = NormalizeName(userName);
|
||||
|
||||
var user = await Store.FindByNameAsync(userName, CancellationToken);
|
||||
|
||||
|
|
@ -603,15 +603,21 @@ namespace Microsoft.AspNetCore.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalize a key (user name, email) for consistent comparisons.
|
||||
/// Normalize user or role name for consistent comparisons.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to normalize.</param>
|
||||
/// <returns>A normalized value representing the specified <paramref name="key"/>.</returns>
|
||||
public virtual string NormalizeKey(string key)
|
||||
{
|
||||
return (KeyNormalizer == null) ? key : KeyNormalizer.Normalize(key);
|
||||
}
|
||||
/// <param name="name">The name to normalize.</param>
|
||||
/// <returns>A normalized value representing the specified <paramref name="name"/>.</returns>
|
||||
public virtual string NormalizeName(string name)
|
||||
=> (KeyNormalizer == null) ? name : KeyNormalizer.NormalizeName(name);
|
||||
|
||||
/// <summary>
|
||||
/// Normalize email for consistent comparisons.
|
||||
/// </summary>
|
||||
/// <param name="email">The email to normalize.</param>
|
||||
/// <returns>A normalized value representing the specified <paramref name="email"/>.</returns>
|
||||
public virtual string NormalizeEmail(string email)
|
||||
=> (KeyNormalizer == null) ? email : KeyNormalizer.NormalizeEmail(email);
|
||||
|
||||
private string ProtectPersonalData(string data)
|
||||
{
|
||||
if (Options.Stores.ProtectPersonalData)
|
||||
|
|
@ -630,7 +636,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
|
||||
public virtual async Task UpdateNormalizedUserNameAsync(TUser user)
|
||||
{
|
||||
var normalizedName = NormalizeKey(await GetUserNameAsync(user));
|
||||
var normalizedName = NormalizeName(await GetUserNameAsync(user));
|
||||
normalizedName = ProtectPersonalData(normalizedName);
|
||||
await Store.SetNormalizedUserNameAsync(user, normalizedName, CancellationToken);
|
||||
}
|
||||
|
|
@ -1199,7 +1205,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
var normalizedRole = NormalizeKey(role);
|
||||
var normalizedRole = NormalizeName(role);
|
||||
if (await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
||||
{
|
||||
return await UserAlreadyInRoleError(user, role);
|
||||
|
|
@ -1232,7 +1238,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
|
||||
foreach (var role in roles.Distinct())
|
||||
{
|
||||
var normalizedRole = NormalizeKey(role);
|
||||
var normalizedRole = NormalizeName(role);
|
||||
if (await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
||||
{
|
||||
return await UserAlreadyInRoleError(user, role);
|
||||
|
|
@ -1260,7 +1266,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
var normalizedRole = NormalizeKey(role);
|
||||
var normalizedRole = NormalizeName(role);
|
||||
if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
||||
{
|
||||
return await UserNotInRoleError(user, role);
|
||||
|
|
@ -1305,7 +1311,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
|
||||
foreach (var role in roles)
|
||||
{
|
||||
var normalizedRole = NormalizeKey(role);
|
||||
var normalizedRole = NormalizeName(role);
|
||||
if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
||||
{
|
||||
return await UserNotInRoleError(user, role);
|
||||
|
|
@ -1348,7 +1354,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
return await userRoleStore.IsInRoleAsync(user, NormalizeKey(role), CancellationToken);
|
||||
return await userRoleStore.IsInRoleAsync(user, NormalizeName(role), CancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -1409,7 +1415,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
throw new ArgumentNullException(nameof(email));
|
||||
}
|
||||
|
||||
email = NormalizeKey(email);
|
||||
email = NormalizeEmail(email);
|
||||
var user = await store.FindByEmailAsync(email, CancellationToken);
|
||||
|
||||
// Need to potentially check all keys
|
||||
|
|
@ -1444,7 +1450,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
if (store != null)
|
||||
{
|
||||
var email = await GetEmailAsync(user);
|
||||
await store.SetNormalizedEmailAsync(user, ProtectPersonalData(NormalizeKey(email)), CancellationToken);
|
||||
await store.SetNormalizedEmailAsync(user, ProtectPersonalData(NormalizeEmail(email)), CancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2097,7 +2103,7 @@ namespace Microsoft.AspNetCore.Identity
|
|||
throw new ArgumentNullException(nameof(roleName));
|
||||
}
|
||||
|
||||
return store.GetUsersInRoleAsync(NormalizeKey(roleName), CancellationToken);
|
||||
return store.GetUsersInRoleAsync(NormalizeName(roleName), CancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
store.VerifyAll();
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DisposeAfterDisposeDoesNotThrow()
|
||||
{
|
||||
|
|
@ -209,4 +208,4 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,6 +269,48 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
store.VerifyAll();
|
||||
}
|
||||
|
||||
private class CustomNormalizer : ILookupNormalizer
|
||||
{
|
||||
public string NormalizeName(string key) => "#"+key;
|
||||
public string NormalizeEmail(string key) => "@" + key;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FindByEmailCallsStoreWithCustomNormalizedEmail()
|
||||
{
|
||||
// Setup
|
||||
var store = new Mock<IUserEmailStore<PocoUser>>();
|
||||
var user = new PocoUser { Email = "Foo" };
|
||||
store.Setup(s => s.FindByEmailAsync("@Foo", CancellationToken.None)).Returns(Task.FromResult(user)).Verifiable();
|
||||
var userManager = MockHelpers.TestUserManager(store.Object);
|
||||
userManager.KeyNormalizer = new CustomNormalizer();
|
||||
|
||||
// Act
|
||||
var result = await userManager.FindByEmailAsync(user.Email);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(user, result);
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FindByNameCallsStoreWithCustomNormalizedName()
|
||||
{
|
||||
// Setup
|
||||
var store = new Mock<IUserEmailStore<PocoUser>>();
|
||||
var user = new PocoUser { UserName = "Foo", Email = "Bar" };
|
||||
store.Setup(s => s.FindByNameAsync("#Foo", CancellationToken.None)).Returns(Task.FromResult(user)).Verifiable();
|
||||
var userManager = MockHelpers.TestUserManager(store.Object);
|
||||
userManager.KeyNormalizer = new CustomNormalizer();
|
||||
|
||||
// Act
|
||||
var result = await userManager.FindByNameAsync(user.UserName);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(user, result);
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddToRolesCallsStore()
|
||||
{
|
||||
|
|
@ -307,6 +349,45 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
store.Verify(s => s.AddToRoleAsync(user, "C", CancellationToken.None), Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddToRolesCallsStoreWithCustomNameNormalizer()
|
||||
{
|
||||
// Setup
|
||||
var store = new Mock<IUserRoleStore<PocoUser>>();
|
||||
var user = new PocoUser { UserName = "Foo" };
|
||||
var roles = new string[] { "A", "B", "C", "C" };
|
||||
store.Setup(s => s.AddToRoleAsync(user, "#A", CancellationToken.None))
|
||||
.Returns(Task.FromResult(0))
|
||||
.Verifiable();
|
||||
store.Setup(s => s.AddToRoleAsync(user, "#B", CancellationToken.None))
|
||||
.Returns(Task.FromResult(0))
|
||||
.Verifiable();
|
||||
store.Setup(s => s.AddToRoleAsync(user, "#C", CancellationToken.None))
|
||||
.Returns(Task.FromResult(0))
|
||||
.Verifiable();
|
||||
|
||||
store.Setup(s => s.UpdateAsync(user, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
|
||||
store.Setup(s => s.IsInRoleAsync(user, "#A", CancellationToken.None))
|
||||
.Returns(Task.FromResult(false))
|
||||
.Verifiable();
|
||||
store.Setup(s => s.IsInRoleAsync(user, "#B", CancellationToken.None))
|
||||
.Returns(Task.FromResult(false))
|
||||
.Verifiable();
|
||||
store.Setup(s => s.IsInRoleAsync(user, "#C", CancellationToken.None))
|
||||
.Returns(Task.FromResult(false))
|
||||
.Verifiable();
|
||||
var userManager = MockHelpers.TestUserManager<PocoUser>(store.Object);
|
||||
userManager.KeyNormalizer = new CustomNormalizer();
|
||||
|
||||
// Act
|
||||
var result = await userManager.AddToRolesAsync(user, roles);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Succeeded);
|
||||
store.VerifyAll();
|
||||
store.Verify(s => s.AddToRoleAsync(user, "#C", CancellationToken.None), Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddToRolesFailsIfUserInRole()
|
||||
{
|
||||
|
|
@ -1664,4 +1745,4 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue