Normalize all lookups with one service

This commit is contained in:
Hao Kung 2015-01-12 12:12:53 -08:00
parent 53b994da19
commit b59440d95f
29 changed files with 507 additions and 119 deletions

View File

@ -3,7 +3,7 @@
"DefaultAdminPassword": "YouShouldChangeThisPassword1!",
"Data": {
"IdentityConnection": {
"Connectionstring": "Server=(localdb)\\mssqllocaldb;Database=IdentityMvc-11-24-14;Trusted_Connection=True;MultipleActiveResultSets=true"
"Connectionstring": "Server=(localdb)\\mssqllocaldb;Database=IdentityMvc-1-7-15;Trusted_Connection=True;MultipleActiveResultSets=true"
}
},
"Identity": {

View File

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
@ -188,16 +187,39 @@ namespace Microsoft.AspNet.Identity.EntityFramework
}
/// <summary>
/// Find a role by name
/// Find a role by normalized name
/// </summary>
/// <param name="name"></param>
/// <param name="normalizedName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual Task<TRole> FindByNameAsync(string name, CancellationToken cancellationToken = default(CancellationToken))
public virtual Task<TRole> FindByNameAsync(string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
return Roles.FirstOrDefaultAsync(u => u.Name.ToUpper() == name.ToUpper(), cancellationToken);
return Roles.FirstOrDefaultAsync(r => r.NormalizedName == normalizedName, cancellationToken);
}
public virtual Task<string> GetNormalizedRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (role == null)
{
throw new ArgumentNullException(nameof(role));
}
return Task.FromResult(role.NormalizedName);
}
public virtual Task SetNormalizedRoleNameAsync(TRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (role == null)
{
throw new ArgumentNullException(nameof(role));
}
role.NormalizedName = normalizedName;
return Task.FromResult(0);
}
private void ThrowIfDisposed()

View File

@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
return AutoSaveChanges ? Context.SaveChangesAsync(cancellationToken) : Task.FromResult(0);
}
public Task<string> GetUserIdAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
public virtual Task<string> GetUserIdAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
return Task.FromResult(ConvertIdToString(user.Id));
}
public Task<string> GetUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
public virtual Task<string> GetUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
@ -100,7 +100,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
return Task.FromResult(user.UserName);
}
public Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
public virtual Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
@ -112,7 +112,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
return Task.FromResult(0);
}
public Task<string> GetNormalizedUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
public virtual Task<string> GetNormalizedUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
@ -123,7 +123,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
return Task.FromResult(user.NormalizedUserName);
}
public Task SetNormalizedUserNameAsync(TUser user, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
public virtual Task SetNormalizedUserNameAsync(TUser user, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
@ -420,7 +420,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
private DbSet<IdentityUserRole<TKey>> UserRoles { get { return Context.Set<IdentityUserRole<TKey>>(); } }
private DbSet<IdentityUserLogin<TKey>> UserLogins { get { return Context.Set<IdentityUserLogin<TKey>>(); } }
public async Task<IList<Claim>> GetClaimsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
public async virtual Task<IList<Claim>> GetClaimsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
if (user == null)
@ -431,7 +431,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
return await UserClaims.Where(uc => uc.UserId.Equals(user.Id)).Select(c => new Claim(c.ClaimType, c.ClaimValue)).ToListAsync(cancellationToken);
}
public async Task AddClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
public async virtual Task AddClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
if (user == null)
@ -448,7 +448,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
}
}
public async Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken = default(CancellationToken))
public async virtual Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
if (user == null)
@ -472,7 +472,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
}
}
public async Task RemoveClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
public async virtual Task RemoveClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
if (user == null)
@ -633,19 +633,40 @@ namespace Microsoft.AspNet.Identity.EntityFramework
return Task.FromResult(user.Email);
}
public virtual Task<string> GetNormalizedEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException("user");
}
return Task.FromResult(user.NormalizedEmail);
}
public virtual Task SetNormalizedEmailAsync(TUser user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException("user");
}
user.NormalizedEmail = normalizedEmail;
return Task.FromResult(0);
}
/// <summary>
/// Find an user by email
/// </summary>
/// <param name="email"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual Task<TUser> FindByEmailAsync(string email, CancellationToken cancellationToken = default(CancellationToken))
public virtual Task<TUser> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
return Users.FirstOrDefaultAsync(u => u.Email == email, cancellationToken);
// todo: ToUpper blows up with Null Ref
//return Users.FirstOrDefaultAsync(u => u.Email.ToUpper() == email.ToUpper(), cancellationToken);
return Users.FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, cancellationToken);
}
/// <summary>
@ -925,7 +946,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
/// <param name="claim"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<IList<TUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken))
public async virtual Task<IList<TUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
@ -940,7 +961,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
&& userclaims.ClaimType == claim.Type
select user;
return (IList<TUser>)await query.ToListAsync(cancellationToken);
return await query.ToListAsync(cancellationToken);
}
/// <summary>
@ -949,7 +970,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
/// <param name="roleName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<IList<TUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken = default(CancellationToken))
public async virtual Task<IList<TUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
@ -967,7 +988,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework
where userrole.RoleId.Equals(role.Id)
select user;
return (IList<TUser>) await query.ToListAsync(cancellationToken);
return await query.ToListAsync(cancellationToken);
}
return new List<TUser>();
}

View File

@ -4,15 +4,15 @@
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Used to normalize a user name
/// Used to normalize keys for consistent lookups
/// </summary>
public interface IUserNameNormalizer
public interface ILookupNormalizer
{
/// <summary>
/// Returns the normalized user name
/// Returns the normalized key
/// </summary>
/// <param name="userName"></param>
/// <param name="key"></param>
/// <returns></returns>
string Normalize(string userName);
string Normalize(string key);
}
}

View File

@ -63,6 +63,26 @@ namespace Microsoft.AspNet.Identity
Task SetRoleNameAsync(TRole role, string roleName,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Get a role's normalized name
/// </summary>
/// <param name="role"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<string> GetNormalizedRoleNameAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Set a role's normalized name
/// </summary>
/// <param name="role"></param>
/// <param name="normalizedName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task SetNormalizedRoleNameAsync(TRole role, string normalizedName,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Finds a role by id
/// </summary>
@ -72,11 +92,11 @@ namespace Microsoft.AspNet.Identity
Task<TRole> FindByIdAsync(string roleId, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Find a role by name
/// Find a role by normalized name
/// </summary>
/// <param name="roleName"></param>
/// <param name="normalizedRoleName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<TRole> FindByNameAsync(string roleName, CancellationToken cancellationToken = default(CancellationToken));
Task<TRole> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
}
}

View File

@ -51,9 +51,28 @@ namespace Microsoft.AspNet.Identity
/// <summary>
/// Returns the user associated with this email
/// </summary>
/// <param name="email"></param>
/// <param name="normalizedEmail"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<TUser> FindByEmailAsync(string email, CancellationToken cancellationToken = default(CancellationToken));
Task<TUser> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Returns the normalized email
/// </summary>
/// <param name="user"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<string> GetNormalizedEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Set the normalized email
/// </summary>
/// <param name="user"></param>
/// <param name="normalizedEmail"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task SetNormalizedEmailAsync(TUser user, string normalizedEmail,
CancellationToken cancellationToken = default(CancellationToken));
}
}

View File

@ -24,7 +24,6 @@ namespace Microsoft.AspNet.Identity
};
}
public virtual IdentityError PasswordMismatch()
{
return new IdentityError

View File

@ -65,6 +65,7 @@ namespace Microsoft.AspNet.Identity
/// Role name
/// </summary>
public virtual string Name { get; set; }
public virtual string NormalizedName { get; set; }
/// <summary>
/// A random value that should change whenever a role is persisted to the store

View File

@ -57,7 +57,7 @@ namespace Microsoft.Framework.DependencyInjection
services.TryAdd(describe.Transient<IUserValidator<TUser>, UserValidator<TUser>>());
services.TryAdd(describe.Transient<IPasswordValidator<TUser>, PasswordValidator<TUser>>());
services.TryAdd(describe.Transient<IPasswordHasher<TUser>, PasswordHasher<TUser>>());
services.TryAdd(describe.Transient<IUserNameNormalizer, UpperInvariantUserNameNormalizer>());
services.TryAdd(describe.Transient<ILookupNormalizer, UpperInvariantLookupNormalizer>());
services.TryAdd(describe.Transient<IRoleValidator<TRole>, RoleValidator<TRole>>());
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAdd(describe.Transient<IdentityErrorDescriber, IdentityErrorDescriber>());

View File

@ -36,6 +36,8 @@ namespace Microsoft.AspNet.Identity
/// </summary>
public virtual string Email { get; set; }
public virtual string NormalizedEmail { get; set; }
/// <summary>
/// True if the email is confirmed, default is false
/// </summary>

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Security.Cryptography;
using Microsoft.AspNet.Security.DataProtection;
namespace Microsoft.AspNet.Identity
{

View File

@ -25,6 +25,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="roleValidator"></param>
public RoleManager(IRoleStore<TRole> store,
IEnumerable<IRoleValidator<TRole>> roleValidators = null,
ILookupNormalizer keyNormalizer = null,
IdentityErrorDescriber errors = null)
{
if (store == null)
@ -32,6 +33,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("store");
}
Store = store;
KeyNormalizer = keyNormalizer ?? new UpperInvariantLookupNormalizer();
ErrorDescriber = errors ?? new IdentityErrorDescriber();
if (roleValidators != null)
@ -58,6 +60,11 @@ namespace Microsoft.AspNet.Identity
/// </summary>
public IdentityErrorDescriber ErrorDescriber { get; set; }
/// <summary>
/// Used to normalize user names, role names, emails for uniqueness
/// </summary>
public ILookupNormalizer KeyNormalizer { get; set; }
/// <summary>
/// Returns an IQueryable of roles if the store is an IQueryableRoleStore
/// </summary>
@ -141,9 +148,24 @@ namespace Microsoft.AspNet.Identity
{
return result;
}
await UpdateNormalizedRoleNameAsync(role, cancellationToken);
return await Store.CreateAsync(role, cancellationToken);
}
/// <summary>
/// Update the user's normalized user name
/// </summary>
/// <param name="user"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task UpdateNormalizedRoleNameAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
var name = await GetRoleNameAsync(role, cancellationToken);
await Store.SetNormalizedRoleNameAsync(role, NormalizeKey(name), cancellationToken);
}
/// <summary>
/// UpdateAsync an existing role
/// </summary>
@ -164,6 +186,7 @@ namespace Microsoft.AspNet.Identity
{
return result;
}
await UpdateNormalizedRoleNameAsync(role, cancellationToken);
return await Store.UpdateAsync(role, cancellationToken);
}
@ -199,9 +222,20 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("roleName");
}
return await FindByNameAsync(roleName, cancellationToken) != null;
return await FindByNameAsync(NormalizeKey(roleName), cancellationToken) != null;
}
/// <summary>
/// Normalize a key (role name) for uniqueness comparisons
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public virtual string NormalizeKey(string key)
{
return (KeyNormalizer == null) ? key : KeyNormalizer.Normalize(key);
}
/// <summary>
/// FindByLoginAsync a role by id
/// </summary>
@ -240,6 +274,7 @@ namespace Microsoft.AspNet.Identity
{
ThrowIfDisposed();
await Store.SetRoleNameAsync(role, name, cancellationToken);
await UpdateNormalizedRoleNameAsync(role, cancellationToken);
return IdentityResult.Success;
}
@ -271,7 +306,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("roleName");
}
return await Store.FindByNameAsync(roleName, cancellationToken);
return await Store.FindByNameAsync(NormalizeKey(roleName), cancellationToken);
}
// IRoleClaimStore methods

View File

@ -8,9 +8,9 @@ using System.Security.Claims;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Security;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Identity
@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Identity
public class SignInManager<TUser> where TUser : class
{
public SignInManager(UserManager<TUser> userManager,
IContextAccessor<HttpContext> contextAccessor,
IHttpContextAccessor contextAccessor,
IClaimsIdentityFactory<TUser> claimsFactory,
IOptions<IdentityOptions> optionsAccessor = null)
{

View File

@ -78,7 +78,5 @@ namespace Microsoft.AspNet.Identity
{
get { return _twoFactorRequired; }
}
}
}

View File

@ -6,22 +6,22 @@ using System;
namespace Microsoft.AspNet.Identity
{
/// <summary>
/// Normalizes user names via ToUpperInvariant()
/// Normalizes via ToUpperInvariant()
/// </summary>
public class UpperInvariantUserNameNormalizer : IUserNameNormalizer
public class UpperInvariantLookupNormalizer : ILookupNormalizer
{
/// <summary>
/// Normalizes user names via ToUpperInvariant()
/// Normalizes via ToUpperInvariant()
/// </summary>
/// <param name="userName"></param>
/// <param name="key"></param>
/// <returns></returns>
public string Normalize(string userName)
public string Normalize(string key)
{
if (userName == null)
if (key == null)
{
return null;
}
return userName.Normalize().ToUpperInvariant();
return key.Normalize().ToUpperInvariant();
}
}
}

View File

@ -30,20 +30,23 @@ namespace Microsoft.AspNet.Identity
private IdentityOptions _options;
/// <summary>
/// Constructor which takes a service provider and user store
/// Constructor
/// </summary>
/// <param name="store"></param>
/// <param name="optionsAccessor"></param>
/// <param name="passwordHasher"></param>
/// <param name="userValidator"></param>
/// <param name="passwordValidator"></param>
/// <param name="claimsIdentityFactory"></param>
/// <param name="userValidators"></param>
/// <param name="passwordValidators"></param>
/// <param name="keyNormalizer"></param>
/// <param name="errors"></param>
/// <param name="tokenProviders"></param>
/// <param name="msgProviders"></param>
public UserManager(IUserStore<TUser> store,
IOptions<IdentityOptions> optionsAccessor = null,
IPasswordHasher<TUser> passwordHasher = null,
IEnumerable<IUserValidator<TUser>> userValidators = null,
IEnumerable<IPasswordValidator<TUser>> passwordValidators = null,
IUserNameNormalizer userNameNormalizer = null,
ILookupNormalizer keyNormalizer = null,
IdentityErrorDescriber errors = null,
IEnumerable<IUserTokenProvider<TUser>> tokenProviders = null,
IEnumerable<IIdentityMessageProvider> msgProviders = null)
@ -55,7 +58,7 @@ namespace Microsoft.AspNet.Identity
Store = store;
Options = optionsAccessor?.Options ?? new IdentityOptions();
PasswordHasher = passwordHasher ?? new PasswordHasher<TUser>();
UserNameNormalizer = userNameNormalizer ?? new UpperInvariantUserNameNormalizer();
KeyNormalizer = keyNormalizer ?? new UpperInvariantLookupNormalizer();
ErrorDescriber = errors ?? new IdentityErrorDescriber();
if (userValidators != null)
{
@ -126,9 +129,9 @@ namespace Microsoft.AspNet.Identity
public IList<IPasswordValidator<TUser>> PasswordValidators { get; } = new List<IPasswordValidator<TUser>>();
/// <summary>
/// Used to normalize user names for uniqueness
/// Used to normalize user names and emails for uniqueness
/// </summary>
public IUserNameNormalizer UserNameNormalizer { get; set; }
public ILookupNormalizer KeyNormalizer { get; set; }
/// <summary>
/// Used to generate public API error messages
@ -353,6 +356,7 @@ namespace Microsoft.AspNet.Identity
await GetUserLockoutStore().SetLockoutEnabledAsync(user, true, cancellationToken);
}
await UpdateNormalizedUserNameAsync(user, cancellationToken);
await UpdateNormalizedEmailAsync(user, cancellationToken);
return await Store.CreateAsync(user, cancellationToken);
}
@ -376,6 +380,7 @@ namespace Microsoft.AspNet.Identity
return result;
}
await UpdateNormalizedUserNameAsync(user, cancellationToken);
await UpdateNormalizedEmailAsync(user, cancellationToken);
return await Store.UpdateAsync(user, cancellationToken);
}
@ -423,7 +428,7 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("userName");
}
userName = NormalizeUserName(userName);
userName = NormalizeKey(userName);
return Store.FindByNameAsync(userName, cancellationToken);
}
@ -467,13 +472,13 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// Normalize a user name for uniqueness comparisons
/// Normalize a key (user name, email) for uniqueness comparisons
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public virtual string NormalizeUserName(string userName)
public virtual string NormalizeKey(string key)
{
return (UserNameNormalizer == null) ? userName : UserNameNormalizer.Normalize(userName);
return (KeyNormalizer == null) ? key : KeyNormalizer.Normalize(key);
}
/// <summary>
@ -485,8 +490,8 @@ namespace Microsoft.AspNet.Identity
public virtual async Task UpdateNormalizedUserNameAsync(TUser user,
CancellationToken cancellationToken = default(CancellationToken))
{
var userName = await GetUserNameAsync(user, cancellationToken);
await Store.SetNormalizedUserNameAsync(user, NormalizeUserName(userName), cancellationToken);
var normalizedName = NormalizeKey(await GetUserNameAsync(user, cancellationToken));
await Store.SetNormalizedUserNameAsync(user, normalizedName, cancellationToken);
}
/// <summary>
@ -1215,10 +1220,10 @@ namespace Microsoft.AspNet.Identity
}
// IUserEmailStore methods
internal IUserEmailStore<TUser> GetEmailStore()
internal IUserEmailStore<TUser> GetEmailStore(bool throwOnFail = true)
{
var cast = Store as IUserEmailStore<TUser>;
if (cast == null)
if (throwOnFail && cast == null)
{
throw new NotSupportedException(Resources.StoreNotIUserEmailStore);
}
@ -1281,9 +1286,27 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("email");
}
return store.FindByEmailAsync(email, cancellationToken);
return store.FindByEmailAsync(NormalizeKey(email), cancellationToken);
}
/// <summary>
/// Update the user's normalized email
/// </summary>
/// <param name="user"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task UpdateNormalizedEmailAsync(TUser user,
CancellationToken cancellationToken = default(CancellationToken))
{
var store = GetEmailStore(throwOnFail: false);
if (store != null)
{
var email = await GetEmailAsync(user, cancellationToken);
await store.SetNormalizedEmailAsync(user, NormalizeKey(email), cancellationToken);
}
}
/// <summary>
/// Get the confirmation token for the user
/// </summary>

View File

@ -76,23 +76,10 @@ namespace Microsoft.AspNet.Identity.EntityFramework.InMemory.Test
var role = new IdentityRole("UpdateRoleName");
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
Assert.Null(await manager.FindByNameAsync("New"));
role.Name = "New";
IdentityResultAssert.IsSuccess(await manager.SetRoleNameAsync(role, "New"));
IdentityResultAssert.IsSuccess(await manager.UpdateAsync(role));
Assert.NotNull(await manager.FindByNameAsync("New"));
Assert.Null(await manager.FindByNameAsync("UpdateAsync"));
}
[Fact]
public async Task CanSetUserName()
{
var manager = TestIdentityFactory.CreateRoleManager();
var role = new IdentityRole("UpdateRoleName");
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
Assert.Null(await manager.FindByNameAsync("New"));
IdentityResultAssert.IsSuccess(await manager.SetRoleNameAsync(role, "New"));
Assert.NotNull(await manager.FindByNameAsync("New"));
Assert.Null(await manager.FindByNameAsync("UpdateAsync"));
}
}
}

View File

@ -4,6 +4,7 @@
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Security;
using Microsoft.AspNet.Identity.Test;
@ -30,7 +31,7 @@ namespace Microsoft.AspNet.Identity.InMemory.Test
var response = new Mock<HttpResponse>();
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
response.Setup(r => r.SignIn(It.Is<AuthenticationProperties>(v => v.IsPersistent == isPersistent), It.IsAny<ClaimsIdentity>())).Verifiable();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
app.UseServices(services =>
{

View File

@ -97,6 +97,17 @@ namespace Microsoft.AspNet.Identity.InMemory
return Task.FromResult(0);
}
public Task<string> GetNormalizedRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(role.NormalizedName);
}
public Task SetNormalizedRoleNameAsync(TRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
{
role.NormalizedName = normalizedName;
return Task.FromResult(0);
}
public IQueryable<TRole> Roles
{
get { return _roles.Values.AsQueryable(); }

View File

@ -108,6 +108,18 @@ namespace Microsoft.AspNet.Identity.InMemory
return Task.FromResult(user.Email);
}
public Task<string> GetNormalizedEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.NormalizedEmail);
}
public Task SetNormalizedEmailAsync(TUser user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
{
user.NormalizedEmail = normalizedEmail;
return Task.FromResult(0);
}
public Task<bool> GetEmailConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.EmailConfirmed);
@ -123,7 +135,7 @@ namespace Microsoft.AspNet.Identity.InMemory
{
return
Task.FromResult(
Users.FirstOrDefault(u => String.Equals(u.Email, email, StringComparison.OrdinalIgnoreCase)));
Users.FirstOrDefault(u => u.NormalizedEmail == email));
}
public Task<DateTimeOffset?> GetLockoutEndDateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
@ -262,7 +274,7 @@ namespace Microsoft.AspNet.Identity.InMemory
{
return
Task.FromResult(
Users.FirstOrDefault(u => String.Equals(u.UserName, userName, StringComparison.OrdinalIgnoreCase)));
Users.FirstOrDefault(u => u.NormalizedUserName == userName));
}
public Task<IdentityResult> DeleteAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))

View File

@ -0,0 +1,6 @@
namespace Microsoft.AspNet.Identity.Test
{
internal interface IHttpContextAccessor<T>
{
}
}

View File

@ -148,6 +148,11 @@ namespace Microsoft.AspNet.Identity.Test
throw new NotImplementedException();
}
public Task<string> GetNormalizedRoleNameAsync(IdentityRole role, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedUserNameAsync(IdentityUser user, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
@ -173,6 +178,11 @@ namespace Microsoft.AspNet.Identity.Test
throw new NotImplementedException();
}
public Task SetNormalizedRoleNameAsync(IdentityRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
}
public Task SetNormalizedUserNameAsync(IdentityUser user, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();

View File

@ -51,5 +51,15 @@ namespace Microsoft.AspNet.Identity.Test
{
return Task.FromResult<string>(null);
}
public Task<string> GetNormalizedRoleNameAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult<string>(null);
}
public Task SetNormalizedRoleNameAsync(TestRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(0);
}
}
}

View File

@ -6,12 +6,51 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Identity.Test
{
public class RoleManagerTest
{
[Fact]
public async Task CreateCallsStore()
{
// Setup
var store = new Mock<IRoleStore<TestRole>>();
var role = new TestRole { Name = "Foo" };
store.Setup(s => s.CreateAsync(role, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
store.Setup(s => s.GetRoleNameAsync(role, CancellationToken.None)).Returns(Task.FromResult(role.Name)).Verifiable();
store.Setup(s => s.SetNormalizedRoleNameAsync(role, role.Name.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
var roleManager = MockHelpers.TestRoleManager(store.Object);
// Act
var result = await roleManager.CreateAsync(role);
// Assert
Assert.True(result.Succeeded);
store.VerifyAll();
}
[Fact]
public async Task UpdateCallsStore()
{
// Setup
var store = new Mock<IRoleStore<TestRole>>();
var role = new TestRole { Name = "Foo" };
store.Setup(s => s.UpdateAsync(role, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
store.Setup(s => s.GetRoleNameAsync(role, CancellationToken.None)).Returns(Task.FromResult(role.Name)).Verifiable();
store.Setup(s => s.SetNormalizedRoleNameAsync(role, role.Name.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
var roleManager = MockHelpers.TestRoleManager(store.Object);
// Act
var result = await roleManager.UpdateAsync(role);
// Assert
Assert.True(result.Succeeded);
store.VerifyAll();
}
[Fact]
public void RolesQueryableFailWhenStoreNotImplemented()
{
@ -20,6 +59,59 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Throws<NotSupportedException>(() => manager.Roles.Count());
}
[Fact]
public async Task FindByNameCallsStoreWithNormalizedName()
{
// Setup
var store = new Mock<IRoleStore<TestRole>>();
var role = new TestRole { Name = "Foo" };
store.Setup(s => s.FindByNameAsync("FOO", CancellationToken.None)).Returns(Task.FromResult(role)).Verifiable();
var manager = MockHelpers.TestRoleManager(store.Object);
// Act
var result = await manager.FindByNameAsync(role.Name);
// Assert
Assert.Equal(role, result);
store.VerifyAll();
}
[Fact]
public async Task CanFindByNameCallsStoreWithoutNormalizedName()
{
// Setup
var store = new Mock<IRoleStore<TestRole>>();
var role = new TestRole { Name = "Foo" };
store.Setup(s => s.FindByNameAsync(role.Name, CancellationToken.None)).Returns(Task.FromResult(role)).Verifiable();
var manager = MockHelpers.TestRoleManager(store.Object);
manager.KeyNormalizer = null;
// Act
var result = await manager.FindByNameAsync(role.Name);
// Assert
Assert.Equal(role, result);
store.VerifyAll();
}
[Fact]
public async Task RoleExistsCallsStoreWithNormalizedName()
{
// Setup
var store = new Mock<IRoleStore<TestRole>>();
var role = new TestRole { Name = "Foo" };
store.Setup(s => s.FindByNameAsync("FOO", CancellationToken.None)).Returns(Task.FromResult(role)).Verifiable();
var manager = MockHelpers.TestRoleManager(store.Object);
// Act
var result = await manager.RoleExistsAsync(role.Name);
// Assert
Assert.True(result);
store.VerifyAll();
}
[Fact]
public void DisposeAfterDisposeDoesNotThrow()
{
@ -107,6 +199,16 @@ namespace Microsoft.AspNet.Identity.Test
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedRoleNameAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
}
public Task SetNormalizedRoleNameAsync(TestRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
}
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Security;
using Microsoft.AspNet.Security;
@ -43,7 +44,7 @@ namespace Microsoft.AspNet.Identity.Test
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var httpContext = new Mock<HttpContext>();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock<SignInManager<IdentityUser>>(userManager.Object,
contextAccessor.Object, claimsManager.Object, options.Object);
@ -78,7 +79,7 @@ namespace Microsoft.AspNet.Identity.Test
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var httpContext = new Mock<HttpContext>();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock<SignInManager<IdentityUser>>(userManager.Object,
contextAccessor.Object, claimsManager.Object, options.Object);
@ -112,7 +113,7 @@ namespace Microsoft.AspNet.Identity.Test
var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero };
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock<SignInManager<IdentityUser>>(userManager.Object,
contextAccessor.Object, claimsManager.Object, options.Object);
@ -146,7 +147,7 @@ namespace Microsoft.AspNet.Identity.Test
var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.FromDays(1) };
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock<SignInManager<IdentityUser>>(userManager.Object,
contextAccessor.Object, claimsManager.Object, options.Object);

View File

@ -7,6 +7,7 @@ using System.Security.Claims;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Security;
using Microsoft.Framework.DependencyInjection;
@ -31,7 +32,7 @@ namespace Microsoft.AspNet.Identity.Test
// TODO: how to functionally test context?
// var context = new DefaultHttpContext(new FeatureCollection());
// var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
// var contextAccessor = new Mock<IHttpContextAccessor>();
// contextAccessor.Setup(a => a.Value).Returns(context);
// app.UseServices(services =>
// {
@ -70,7 +71,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Throws<ArgumentNullException>("userManager", () => new SignInManager<IdentityUser>(null, null, null, null));
var userManager = MockHelpers.MockUserManager<IdentityUser>().Object;
Assert.Throws<ArgumentNullException>("contextAccessor", () => new SignInManager<IdentityUser>(userManager, null, null, null));
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
Assert.Throws<ArgumentNullException>("contextAccessor", () => new SignInManager<IdentityUser>(userManager, contextAccessor.Object, null, null));
var context = new Mock<HttpContext>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
@ -93,7 +94,7 @@ namespace Microsoft.AspNet.Identity.Test
// var response = new Mock<HttpResponse>();
// context.Setup(c => c.Response).Returns(response.Object).Verifiable();
// response.Setup(r => r.SignIn(testIdentity, It.IsAny<AuthenticationProperties>())).Verifiable();
// var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
// var contextAccessor = new Mock<IHttpContextAccessor>();
// contextAccessor.Setup(a => a.Value).Returns(context.Object);
// var helper = new HttpAuthenticationManager(contextAccessor.Object);
@ -117,7 +118,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.IsLockedOutAsync(user, CancellationToken.None)).ReturnsAsync(true).Verifiable();
manager.Setup(m => m.FindByNameAsync(user.UserName, CancellationToken.None)).ReturnsAsync(user).Verifiable();
var context = new Mock<HttpContext>();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -152,7 +153,7 @@ namespace Microsoft.AspNet.Identity.Test
var response = new Mock<HttpResponse>();
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
response.Setup(r => r.SignIn(It.Is<AuthenticationProperties>(v => v.IsPersistent == isPersistent), It.IsAny<ClaimsIdentity>())).Verifiable();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -189,7 +190,7 @@ namespace Microsoft.AspNet.Identity.Test
var response = new Mock<HttpResponse>();
response.Setup(r => r.SignIn(It.IsAny<AuthenticationProperties>(), It.IsAny<ClaimsIdentity>())).Verifiable();
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -238,7 +239,7 @@ namespace Microsoft.AspNet.Identity.Test
var response = new Mock<HttpResponse>();
response.Setup(r => r.SignIn(It.Is<ClaimsIdentity>(id => id.Name == user.Id))).Verifiable();
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -282,7 +283,7 @@ namespace Microsoft.AspNet.Identity.Test
response.Setup(r => r.SignIn(
It.Is<AuthenticationProperties>(v => v.IsPersistent == isPersistent),
It.Is<ClaimsIdentity>(i => i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider))).Verifiable();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -342,7 +343,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.GetUserNameAsync(user, CancellationToken.None)).ReturnsAsync(user.UserName).Verifiable();
var context = new Mock<HttpContext>();
var response = new Mock<HttpResponse>();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
var twoFactorInfo = new SignInManager<TestUser>.TwoFactorAuthenticationInfo { UserId = user.Id };
var loginProvider = "loginprovider";
var id = SignInManager<TestUser>.StoreTwoFactorInfo(user.Id, externalLogin ? loginProvider : null);
@ -397,7 +398,7 @@ namespace Microsoft.AspNet.Identity.Test
var manager = MockHelpers.MockUserManager<TestUser>();
var context = new Mock<HttpContext>();
var response = new Mock<HttpResponse>();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
var options = new Mock<IOptions<IdentityOptions>>();
@ -452,7 +453,7 @@ namespace Microsoft.AspNet.Identity.Test
id.AddClaim(new Claim(ClaimTypes.Name, user.Id));
var authResult = new AuthenticationResult(id, new AuthenticationProperties(), new AuthenticationDescription());
context.Setup(c => c.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType)).ReturnsAsync(authResult).Verifiable();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -487,7 +488,7 @@ namespace Microsoft.AspNet.Identity.Test
response.Setup(r => r.SignOut(authenticationType)).Verifiable();
response.Setup(r => r.SignOut(IdentityOptions.TwoFactorUserIdCookieAuthenticationType)).Verifiable();
response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationType)).Verifiable();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -518,7 +519,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.FindByNameAsync(user.UserName, CancellationToken.None)).ReturnsAsync(user).Verifiable();
manager.Setup(m => m.CheckPasswordAsync(user, "bogus", CancellationToken.None)).ReturnsAsync(false).Verifiable();
var context = new Mock<HttpContext>();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -543,7 +544,7 @@ namespace Microsoft.AspNet.Identity.Test
var manager = MockHelpers.MockUserManager<TestUser>();
manager.Setup(m => m.FindByNameAsync("bogus", CancellationToken.None)).ReturnsAsync(null).Verifiable();
var context = new Mock<HttpContext>();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -579,7 +580,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.FindByNameAsync(user.UserName, CancellationToken.None)).ReturnsAsync(user).Verifiable();
manager.Setup(m => m.CheckPasswordAsync(user, "bogus", CancellationToken.None)).ReturnsAsync(false).Verifiable();
var context = new Mock<HttpContext>();
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -618,7 +619,7 @@ namespace Microsoft.AspNet.Identity.Test
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
response.Setup(r => r.SignIn(It.Is<AuthenticationProperties>(v => v.IsPersistent == false), It.IsAny<ClaimsIdentity>())).Verifiable();
}
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
@ -659,7 +660,7 @@ namespace Microsoft.AspNet.Identity.Test
response.Setup(r => r.SignIn(It.Is<AuthenticationProperties>(v => v.IsPersistent == false), It.IsAny<ClaimsIdentity>())).Verifiable();
}
var contextAccessor = new Mock<IContextAccessor<HttpContext>>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();

View File

@ -43,6 +43,29 @@ namespace Microsoft.AspNet.Identity.Test
var store = new Mock<IUserStore<TestUser>>();
var user = new TestUser { UserName = "Foo" };
store.Setup(s => s.CreateAsync(user, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
store.Setup(s => s.GetUserNameAsync(user, CancellationToken.None)).Returns(Task.FromResult(user.UserName)).Verifiable();
store.Setup(s => s.SetNormalizedUserNameAsync(user, user.UserName.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
// Act
var result = await userManager.CreateAsync(user);
// Assert
Assert.True(result.Succeeded);
store.VerifyAll();
}
[Fact]
public async Task CreateCallsUpdateEmailStore()
{
// Setup
var store = new Mock<IUserEmailStore<TestUser>>();
var user = new TestUser { UserName = "Foo", Email = "Foo@foo.com" };
store.Setup(s => s.CreateAsync(user, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
store.Setup(s => s.GetUserNameAsync(user, CancellationToken.None)).Returns(Task.FromResult(user.UserName)).Verifiable();
store.Setup(s => s.GetEmailAsync(user, CancellationToken.None)).Returns(Task.FromResult(user.Email)).Verifiable();
store.Setup(s => s.SetNormalizedEmailAsync(user, user.Email.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
store.Setup(s => s.SetNormalizedUserNameAsync(user, user.UserName.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
// Act
@ -76,6 +99,29 @@ namespace Microsoft.AspNet.Identity.Test
// Setup
var store = new Mock<IUserStore<TestUser>>();
var user = new TestUser { UserName = "Foo" };
store.Setup(s => s.GetUserNameAsync(user, CancellationToken.None)).Returns(Task.FromResult(user.UserName)).Verifiable();
store.Setup(s => s.SetNormalizedUserNameAsync(user, user.UserName.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
store.Setup(s => s.UpdateAsync(user, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
var userManager = MockHelpers.TestUserManager(store.Object);
// Act
var result = await userManager.UpdateAsync(user);
// Assert
Assert.True(result.Succeeded);
store.VerifyAll();
}
[Fact]
public async Task UpdateWillUpdateNormalizedEmail()
{
// Setup
var store = new Mock<IUserEmailStore<TestUser>>();
var user = new TestUser { UserName = "Foo", Email = "email" };
store.Setup(s => s.GetUserNameAsync(user, CancellationToken.None)).Returns(Task.FromResult(user.UserName)).Verifiable();
store.Setup(s => s.GetEmailAsync(user, CancellationToken.None)).Returns(Task.FromResult(user.Email)).Verifiable();
store.Setup(s => s.SetNormalizedUserNameAsync(user, user.UserName.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
store.Setup(s => s.SetNormalizedEmailAsync(user, user.Email.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
store.Setup(s => s.UpdateAsync(user, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
var userManager = MockHelpers.TestUserManager(store.Object);
@ -93,7 +139,9 @@ namespace Microsoft.AspNet.Identity.Test
// Setup
var store = new Mock<IUserStore<TestUser>>();
var user = new TestUser();
store.Setup(s => s.SetUserNameAsync(user, It.IsAny<string>(), CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
store.Setup(s => s.SetUserNameAsync(user, "foo", CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
store.Setup(s => s.GetUserNameAsync(user, CancellationToken.None)).Returns(Task.FromResult("foo")).Verifiable();
store.Setup(s => s.SetNormalizedUserNameAsync(user, "FOO", CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
store.Setup(s => s.UpdateAsync(user, CancellationToken.None)).Returns(Task.FromResult(IdentityResult.Success)).Verifiable();
var userManager = MockHelpers.TestUserManager(store.Object);
@ -146,8 +194,8 @@ namespace Microsoft.AspNet.Identity.Test
var store = new Mock<IUserStore<TestUser>>();
var user = new TestUser {UserName="Foo"};
store.Setup(s => s.FindByNameAsync(user.UserName, CancellationToken.None)).Returns(Task.FromResult(user)).Verifiable();
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
userManager.UserNameNormalizer = null;
var userManager = MockHelpers.TestUserManager(store.Object);
userManager.KeyNormalizer = null;
// Act
var result = await userManager.FindByNameAsync(user.UserName);
@ -157,6 +205,41 @@ namespace Microsoft.AspNet.Identity.Test
store.VerifyAll();
}
[Fact]
public async Task FindByEmailCallsStoreWithNormalizedEmail()
{
// Setup
var store = new Mock<IUserEmailStore<TestUser>>();
var user = new TestUser { Email = "Foo" };
store.Setup(s => s.FindByEmailAsync(user.Email.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(user)).Verifiable();
var userManager = MockHelpers.TestUserManager(store.Object);
// Act
var result = await userManager.FindByEmailAsync(user.Email);
// Assert
Assert.Equal(user, result);
store.VerifyAll();
}
[Fact]
public async Task CanFindByEmailCallsStoreWithoutNormalizedEmail()
{
// Setup
var store = new Mock<IUserEmailStore<TestUser>>();
var user = new TestUser { Email = "Foo" };
store.Setup(s => s.FindByEmailAsync(user.Email, CancellationToken.None)).Returns(Task.FromResult(user)).Verifiable();
var userManager = MockHelpers.TestUserManager(store.Object);
userManager.KeyNormalizer = null;
// Act
var result = await userManager.FindByEmailAsync(user.Email);
// Assert
Assert.Equal(user, result);
store.VerifyAll();
}
[Fact]
public async Task AddToRolesCallsStore()
{
@ -961,6 +1044,16 @@ namespace Microsoft.AspNet.Identity.Test
{
return Task.FromResult<IList<TestUser>>(new List<TestUser>());
}
public Task<string> GetNormalizedEmailAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult("");
}
public Task SetNormalizedEmailAsync(TestUser user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(0);
}
}
private class NoOpTokenProvider : IUserTokenProvider<TestUser>
@ -1228,6 +1321,16 @@ namespace Microsoft.AspNet.Identity.Test
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedEmailAsync(TestUser user, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
}
public Task SetNormalizedEmailAsync(TestUser user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
{
throw new NotImplementedException();
}
}
[Fact]
@ -1245,7 +1348,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Options.User.RequireUniqueEmail = true;
var user = new TestUser() { UserName = "dupeEmail", Email = "dupe@email.com" };
var user2 = new TestUser() { UserName = "dupeEmail2", Email = "dupe@email.com" };
store.Setup(s => s.FindByEmailAsync(user.Email, CancellationToken.None))
store.Setup(s => s.FindByEmailAsync("DUPE@EMAIL.COM", CancellationToken.None))
.Returns(Task.FromResult(user2))
.Verifiable();
store.Setup(s => s.GetUserIdAsync(user2, CancellationToken.None))

View File

@ -20,21 +20,17 @@ namespace Microsoft.AspNet.Identity.Test
return mgr;
}
public static Mock<RoleManager<TRole>> MockRoleManager<TRole>() where TRole : class
public static Mock<RoleManager<TRole>> MockRoleManager<TRole>(IRoleStore<TRole> store = null) where TRole : class
{
var store = new Mock<IRoleStore<TRole>>();
store = store ?? new Mock<IRoleStore<TRole>>().Object;
var roles = new List<IRoleValidator<TRole>>();
roles.Add(new RoleValidator<TRole>());
return new Mock<RoleManager<TRole>>(store.Object, roles, null);
return new Mock<RoleManager<TRole>>(store, roles, null, null);
}
public static UserManager<TUser> TestUserManager<TUser>() where TUser : class
{
return TestUserManager(new Mock<IUserStore<TUser>>().Object);
}
public static UserManager<TUser> TestUserManager<TUser>(IUserStore<TUser> store) where TUser : class
public static UserManager<TUser> TestUserManager<TUser>(IUserStore<TUser> store = null) where TUser : class
{
store = store ?? new Mock<IUserStore<TUser>>().Object;
var validator = new Mock<IUserValidator<TUser>>();
var userManager = new UserManager<TUser>(store);
userManager.UserValidators.Add(validator.Object);
@ -43,5 +39,14 @@ namespace Microsoft.AspNet.Identity.Test
.Returns(Task.FromResult(IdentityResult.Success)).Verifiable();
return userManager;
}
public static RoleManager<TRole> TestRoleManager<TRole>(IRoleStore<TRole> store = null) where TRole : class
{
store = store ?? new Mock<IRoleStore<TRole>>().Object;
var roles = new List<IRoleValidator<TRole>>();
roles.Add(new RoleValidator<TRole>());
return new RoleManager<TRole>(store, roles);
}
}
}

View File

@ -1016,10 +1016,10 @@ namespace Microsoft.AspNet.Identity.Test
Assert.False(await manager.RoleExistsAsync(role.Name));
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
Assert.True(await manager.RoleExistsAsync(role.Name));
role.Name = "Changed";
IdentityResultAssert.IsSuccess(await manager.SetRoleNameAsync(role, "Changed"));
IdentityResultAssert.IsSuccess(await manager.UpdateAsync(role));
Assert.False(await manager.RoleExistsAsync("update"));
Assert.Equal(role, await manager.FindByNameAsync(role.Name));
Assert.Equal(role, await manager.FindByNameAsync("Changed"));
}
[Fact]