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
|
public partial interface ILookupNormalizer
|
||||||
{
|
{
|
||||||
string Normalize(string key);
|
string NormalizeEmail(string email);
|
||||||
|
string NormalizeName(string name);
|
||||||
}
|
}
|
||||||
public partial interface ILookupProtector
|
public partial interface ILookupProtector
|
||||||
{
|
{
|
||||||
|
|
@ -450,10 +451,11 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
[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 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 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
|
public partial class UserClaimsPrincipalFactory<TUser> : Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<TUser> where TUser : class
|
||||||
{
|
{
|
||||||
|
|
@ -600,7 +602,8 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
public virtual System.Threading.Tasks.Task<bool> IsLockedOutAsync(TUser user) { throw null; }
|
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 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]
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Identity.IdentityResult> RedeemTwoFactorRecoveryCodeAsync(TUser user, string code) { throw null; }
|
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) { }
|
public virtual void RegisterTokenProvider(string providerName, Microsoft.AspNetCore.Identity.IUserTwoFactorTokenProvider<TUser> provider) { }
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,23 @@
|
||||||
namespace Microsoft.AspNetCore.Identity
|
namespace Microsoft.AspNetCore.Identity
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides an abstraction for normalizing keys for lookup purposes.
|
/// Provides an abstraction for normalizing keys (emails/names) for lookup purposes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ILookupNormalizer
|
public interface ILookupNormalizer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a normalized representation of the specified <paramref name="key"/>.
|
/// Returns a normalized representation of the specified <paramref name="name"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key to normalize.</param>
|
/// <param name="name">The key to normalize.</param>
|
||||||
/// <returns>A normalized representation of the specified <paramref name="key"/>.</returns>
|
/// <returns>A normalized representation of the specified <paramref name="name"/>.</returns>
|
||||||
string Normalize(string key);
|
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>
|
/// <returns>A normalized representation of the specified <paramref name="key"/>.</returns>
|
||||||
public virtual string NormalizeKey(string key)
|
public virtual string NormalizeKey(string key)
|
||||||
{
|
{
|
||||||
return (KeyNormalizer == null) ? key : KeyNormalizer.Normalize(key);
|
return (KeyNormalizer == null) ? key : KeyNormalizer.NormalizeName(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,27 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implements <see cref="ILookupNormalizer"/> by converting keys to their upper cased invariant culture representation.
|
/// Implements <see cref="ILookupNormalizer"/> by converting keys to their upper cased invariant culture representation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UpperInvariantLookupNormalizer : ILookupNormalizer
|
public sealed class UpperInvariantLookupNormalizer : ILookupNormalizer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a normalized representation of the specified <paramref name="key"/>
|
/// Returns a normalized representation of the specified <paramref name="name"/>.
|
||||||
/// by converting keys to their upper cased invariant culture representation.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key to normalize.</param>
|
/// <param name="name">The key to normalize.</param>
|
||||||
/// <returns>A normalized representation of the specified <paramref name="key"/>.</returns>
|
/// <returns>A normalized representation of the specified <paramref name="name"/>.</returns>
|
||||||
public virtual string Normalize(string key)
|
public string NormalizeName(string name)
|
||||||
{
|
{
|
||||||
if (key == null)
|
if (name == null)
|
||||||
{
|
{
|
||||||
return 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -547,7 +547,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(userName));
|
throw new ArgumentNullException(nameof(userName));
|
||||||
}
|
}
|
||||||
userName = NormalizeKey(userName);
|
userName = NormalizeName(userName);
|
||||||
|
|
||||||
var user = await Store.FindByNameAsync(userName, CancellationToken);
|
var user = await Store.FindByNameAsync(userName, CancellationToken);
|
||||||
|
|
||||||
|
|
@ -603,14 +603,20 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Normalize a key (user name, email) for consistent comparisons.
|
/// Normalize user or role name for consistent comparisons.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The key to normalize.</param>
|
/// <param name="name">The name to normalize.</param>
|
||||||
/// <returns>A normalized value representing the specified <paramref name="key"/>.</returns>
|
/// <returns>A normalized value representing the specified <paramref name="name"/>.</returns>
|
||||||
public virtual string NormalizeKey(string key)
|
public virtual string NormalizeName(string name)
|
||||||
{
|
=> (KeyNormalizer == null) ? name : KeyNormalizer.NormalizeName(name);
|
||||||
return (KeyNormalizer == null) ? key : KeyNormalizer.Normalize(key);
|
|
||||||
}
|
/// <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)
|
private string ProtectPersonalData(string data)
|
||||||
{
|
{
|
||||||
|
|
@ -630,7 +636,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
|
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
|
||||||
public virtual async Task UpdateNormalizedUserNameAsync(TUser user)
|
public virtual async Task UpdateNormalizedUserNameAsync(TUser user)
|
||||||
{
|
{
|
||||||
var normalizedName = NormalizeKey(await GetUserNameAsync(user));
|
var normalizedName = NormalizeName(await GetUserNameAsync(user));
|
||||||
normalizedName = ProtectPersonalData(normalizedName);
|
normalizedName = ProtectPersonalData(normalizedName);
|
||||||
await Store.SetNormalizedUserNameAsync(user, normalizedName, CancellationToken);
|
await Store.SetNormalizedUserNameAsync(user, normalizedName, CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
@ -1199,7 +1205,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
throw new ArgumentNullException(nameof(user));
|
throw new ArgumentNullException(nameof(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
var normalizedRole = NormalizeKey(role);
|
var normalizedRole = NormalizeName(role);
|
||||||
if (await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
if (await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
||||||
{
|
{
|
||||||
return await UserAlreadyInRoleError(user, role);
|
return await UserAlreadyInRoleError(user, role);
|
||||||
|
|
@ -1232,7 +1238,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
|
|
||||||
foreach (var role in roles.Distinct())
|
foreach (var role in roles.Distinct())
|
||||||
{
|
{
|
||||||
var normalizedRole = NormalizeKey(role);
|
var normalizedRole = NormalizeName(role);
|
||||||
if (await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
if (await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
||||||
{
|
{
|
||||||
return await UserAlreadyInRoleError(user, role);
|
return await UserAlreadyInRoleError(user, role);
|
||||||
|
|
@ -1260,7 +1266,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
throw new ArgumentNullException(nameof(user));
|
throw new ArgumentNullException(nameof(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
var normalizedRole = NormalizeKey(role);
|
var normalizedRole = NormalizeName(role);
|
||||||
if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
||||||
{
|
{
|
||||||
return await UserNotInRoleError(user, role);
|
return await UserNotInRoleError(user, role);
|
||||||
|
|
@ -1305,7 +1311,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
|
|
||||||
foreach (var role in roles)
|
foreach (var role in roles)
|
||||||
{
|
{
|
||||||
var normalizedRole = NormalizeKey(role);
|
var normalizedRole = NormalizeName(role);
|
||||||
if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken))
|
||||||
{
|
{
|
||||||
return await UserNotInRoleError(user, role);
|
return await UserNotInRoleError(user, role);
|
||||||
|
|
@ -1348,7 +1354,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(user));
|
throw new ArgumentNullException(nameof(user));
|
||||||
}
|
}
|
||||||
return await userRoleStore.IsInRoleAsync(user, NormalizeKey(role), CancellationToken);
|
return await userRoleStore.IsInRoleAsync(user, NormalizeName(role), CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1409,7 +1415,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
throw new ArgumentNullException(nameof(email));
|
throw new ArgumentNullException(nameof(email));
|
||||||
}
|
}
|
||||||
|
|
||||||
email = NormalizeKey(email);
|
email = NormalizeEmail(email);
|
||||||
var user = await store.FindByEmailAsync(email, CancellationToken);
|
var user = await store.FindByEmailAsync(email, CancellationToken);
|
||||||
|
|
||||||
// Need to potentially check all keys
|
// Need to potentially check all keys
|
||||||
|
|
@ -1444,7 +1450,7 @@ namespace Microsoft.AspNetCore.Identity
|
||||||
if (store != null)
|
if (store != null)
|
||||||
{
|
{
|
||||||
var email = await GetEmailAsync(user);
|
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));
|
throw new ArgumentNullException(nameof(roleName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return store.GetUsersInRoleAsync(NormalizeKey(roleName), CancellationToken);
|
return store.GetUsersInRoleAsync(NormalizeName(roleName), CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,6 @@ namespace Microsoft.AspNetCore.Identity.Test
|
||||||
store.VerifyAll();
|
store.VerifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void DisposeAfterDisposeDoesNotThrow()
|
public void DisposeAfterDisposeDoesNotThrow()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,48 @@ namespace Microsoft.AspNetCore.Identity.Test
|
||||||
store.VerifyAll();
|
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]
|
[Fact]
|
||||||
public async Task AddToRolesCallsStore()
|
public async Task AddToRolesCallsStore()
|
||||||
{
|
{
|
||||||
|
|
@ -307,6 +349,45 @@ namespace Microsoft.AspNetCore.Identity.Test
|
||||||
store.Verify(s => s.AddToRoleAsync(user, "C", CancellationToken.None), Times.Once());
|
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]
|
[Fact]
|
||||||
public async Task AddToRolesFailsIfUserInRole()
|
public async Task AddToRolesFailsIfUserInRole()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue