Allow multiple validators

Role/Password/User validators are now IEnumerable instead of a single
instance
This commit is contained in:
Hao Kung 2014-12-04 13:06:41 -08:00
parent 0654c86d61
commit 5658af6b61
12 changed files with 159 additions and 95 deletions

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Identity
/// Validate the password for the user /// Validate the password for the user
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
Task<IdentityResult> ValidateAsync(TUser user, string password, UserManager<TUser> manager, Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password,
CancellationToken cancellationToken = default(CancellationToken)); CancellationToken cancellationToken = default(CancellationToken));
} }
} }

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="manager"></param> /// <param name="manager"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public virtual Task<IdentityResult> ValidateAsync(TUser user, string password, UserManager<TUser> manager, public virtual Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password,
CancellationToken cancellationToken = default(CancellationToken)) CancellationToken cancellationToken = default(CancellationToken))
{ {
if (password == null) if (password == null)

View File

@ -24,18 +24,21 @@ namespace Microsoft.AspNet.Identity
/// </summary> /// </summary>
/// <param name="store">The IRoleStore commits changes via the UpdateAsync/CreateAsync methods</param> /// <param name="store">The IRoleStore commits changes via the UpdateAsync/CreateAsync methods</param>
/// <param name="roleValidator"></param> /// <param name="roleValidator"></param>
public RoleManager(IRoleStore<TRole> store, IRoleValidator<TRole> roleValidator) public RoleManager(IRoleStore<TRole> store, IEnumerable<IRoleValidator<TRole>> roleValidators)
{ {
if (store == null) if (store == null)
{ {
throw new ArgumentNullException("store"); throw new ArgumentNullException("store");
} }
if (roleValidator == null)
{
throw new ArgumentNullException("roleValidator");
}
RoleValidator = roleValidator;
Store = store; Store = store;
if (roleValidators != null)
{
foreach (var v in roleValidators)
{
RoleValidators.Add(v);
}
}
} }
/// <summary> /// <summary>
@ -46,7 +49,7 @@ namespace Microsoft.AspNet.Identity
/// <summary> /// <summary>
/// Used to validate roles before persisting changes /// Used to validate roles before persisting changes
/// </summary> /// </summary>
public IRoleValidator<TRole> RoleValidator { get; set; } public IList<IRoleValidator<TRole>> RoleValidators { get; } = new List<IRoleValidator<TRole>>();
/// <summary> /// <summary>
/// Returns an IQueryable of roles if the store is an IQueryableRoleStore /// Returns an IQueryable of roles if the store is an IQueryableRoleStore
@ -99,8 +102,16 @@ namespace Microsoft.AspNet.Identity
private async Task<IdentityResult> ValidateRoleInternal(TRole role, CancellationToken cancellationToken) private async Task<IdentityResult> ValidateRoleInternal(TRole role, CancellationToken cancellationToken)
{ {
return (RoleValidator == null) ? IdentityResult.Success : var errors = new List<string>();
await RoleValidator.ValidateAsync(this, role, cancellationToken); foreach (var v in RoleValidators)
{
var result = await v.ValidateAsync(this, role, cancellationToken);
if (!result.Succeeded)
{
errors.AddRange(result.Errors);
}
}
return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
} }
/// <summary> /// <summary>

View File

@ -41,8 +41,8 @@ namespace Microsoft.AspNet.Identity
public UserManager(IUserStore<TUser> store, public UserManager(IUserStore<TUser> store,
IOptions<IdentityOptions> optionsAccessor, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TUser> passwordHasher, IPasswordHasher<TUser> passwordHasher,
IUserValidator<TUser> userValidator, IEnumerable<IUserValidator<TUser>> userValidators,
IPasswordValidator<TUser> passwordValidator, IEnumerable<IPasswordValidator<TUser>> passwordValidators,
IUserNameNormalizer userNameNormalizer, IUserNameNormalizer userNameNormalizer,
IEnumerable<IUserTokenProvider<TUser>> tokenProviders, IEnumerable<IUserTokenProvider<TUser>> tokenProviders,
IEnumerable<IIdentityMessageProvider> msgProviders) IEnumerable<IIdentityMessageProvider> msgProviders)
@ -62,11 +62,21 @@ namespace Microsoft.AspNet.Identity
Store = store; Store = store;
Options = optionsAccessor.Options; Options = optionsAccessor.Options;
PasswordHasher = passwordHasher; PasswordHasher = passwordHasher;
UserValidator = userValidator;
PasswordValidator = passwordValidator;
UserNameNormalizer = userNameNormalizer; UserNameNormalizer = userNameNormalizer;
// TODO: Email/Sms/Token services if (userValidators != null)
{
foreach (var v in userValidators)
{
UserValidators.Add(v);
}
}
if (passwordValidators != null)
{
foreach (var v in passwordValidators)
{
PasswordValidators.Add(v);
}
}
if (tokenProviders != null) if (tokenProviders != null)
{ {
foreach (var tokenProvider in tokenProviders) foreach (var tokenProvider in tokenProviders)
@ -114,12 +124,12 @@ namespace Microsoft.AspNet.Identity
/// <summary> /// <summary>
/// Used to validate users before persisting changes /// Used to validate users before persisting changes
/// </summary> /// </summary>
public IUserValidator<TUser> UserValidator { get; set; } public IList<IUserValidator<TUser>> UserValidators { get; } = new List<IUserValidator<TUser>>();
/// <summary> /// <summary>
/// Used to validate passwords before persisting changes /// Used to validate passwords before persisting changes
/// </summary> /// </summary>
public IPasswordValidator<TUser> PasswordValidator { get; set; } public IList<IPasswordValidator<TUser>> PasswordValidators { get; } = new List<IPasswordValidator<TUser>>();
/// <summary> /// <summary>
/// Used to normalize user names for uniqueness /// Used to normalize user names for uniqueness
@ -291,9 +301,30 @@ namespace Microsoft.AspNet.Identity
private async Task<IdentityResult> ValidateUserInternal(TUser user, CancellationToken cancellationToken) private async Task<IdentityResult> ValidateUserInternal(TUser user, CancellationToken cancellationToken)
{ {
return (UserValidator == null) var errors = new List<string>();
? IdentityResult.Success foreach (var v in UserValidators)
: await UserValidator.ValidateAsync(this, user, cancellationToken); {
var result = await v.ValidateAsync(this, user, cancellationToken);
if (!result.Succeeded)
{
errors.AddRange(result.Errors);
}
}
return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
}
private async Task<IdentityResult> ValidatePasswordInternal(TUser user, string password, CancellationToken cancellationToken)
{
var errors = new List<string>();
foreach (var v in PasswordValidators)
{
var result = await v.ValidateAsync(this, user, password, cancellationToken);
if (!result.Succeeded)
{
errors.AddRange(result.Errors);
}
}
return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
} }
/// <summary> /// <summary>
@ -629,13 +660,10 @@ namespace Microsoft.AspNet.Identity
internal async Task<IdentityResult> UpdatePasswordInternal(IUserPasswordStore<TUser> passwordStore, internal async Task<IdentityResult> UpdatePasswordInternal(IUserPasswordStore<TUser> passwordStore,
TUser user, string newPassword, CancellationToken cancellationToken) TUser user, string newPassword, CancellationToken cancellationToken)
{ {
if (PasswordValidator != null) var validate = await ValidatePasswordInternal(user, newPassword, cancellationToken);
if (!validate.Succeeded)
{ {
var result = await PasswordValidator.ValidateAsync(user, newPassword, this, cancellationToken); return validate;
if (!result.Succeeded)
{
return result;
}
} }
await await
passwordStore.SetPasswordHashAsync(user, PasswordHasher.HashPassword(user, newPassword), cancellationToken); passwordStore.SetPasswordHashAsync(user, PasswordHasher.HashPassword(user, newPassword), cancellationToken);

View File

@ -1,18 +1,16 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder; using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Security; using Microsoft.AspNet.Http.Security;
using Microsoft.AspNet.Identity.Test; using Microsoft.AspNet.Identity.Test;
using Microsoft.AspNet.Security.Cookies;
using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Moq;
using System.Security.Claims;
using System.Threading.Tasks;
using Xunit;
using Microsoft.Framework.Runtime.Infrastructure; using Microsoft.Framework.Runtime.Infrastructure;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Identity.InMemory.Test namespace Microsoft.AspNet.Identity.InMemory.Test
{ {

View File

@ -187,7 +187,7 @@ namespace Microsoft.AspNet.Identity.Test
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<IdentityResult> ValidateAsync(IdentityUser user, string password, UserManager<IdentityUser> manager, CancellationToken cancellationToken = default(CancellationToken)) public Task<IdentityResult> ValidateAsync(UserManager<IdentityUser> manager, IdentityUser user, string password, CancellationToken cancellationToken = default(CancellationToken))
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Identity.Test
// Act // Act
// Assert // Assert
await Assert.ThrowsAsync<ArgumentNullException>("password", () => validator.ValidateAsync(null, null, null)); await Assert.ThrowsAsync<ArgumentNullException>("password", () => validator.ValidateAsync(null, null, null));
await Assert.ThrowsAsync<ArgumentNullException>("manager", () => validator.ValidateAsync(null, "foo", null)); await Assert.ThrowsAsync<ArgumentNullException>("manager", () => validator.ValidateAsync(null, null, "foo"));
} }
@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Options.Password.RequireNonLetterOrDigit = false; manager.Options.Password.RequireNonLetterOrDigit = false;
manager.Options.Password.RequireLowercase = false; manager.Options.Password.RequireLowercase = false;
manager.Options.Password.RequireDigit = false; manager.Options.Password.RequireDigit = false;
IdentityResultAssert.IsFailure(await valid.ValidateAsync(null, input, manager), error); IdentityResultAssert.IsFailure(await valid.ValidateAsync(manager, null, input), error);
} }
[Theory] [Theory]
@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Options.Password.RequireNonLetterOrDigit = false; manager.Options.Password.RequireNonLetterOrDigit = false;
manager.Options.Password.RequireLowercase = false; manager.Options.Password.RequireLowercase = false;
manager.Options.Password.RequireDigit = false; manager.Options.Password.RequireDigit = false;
IdentityResultAssert.IsSuccess(await valid.ValidateAsync(null, input, manager)); IdentityResultAssert.IsSuccess(await valid.ValidateAsync(manager, null, input));
} }
[Theory] [Theory]
@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Options.Password.RequireLowercase = false; manager.Options.Password.RequireLowercase = false;
manager.Options.Password.RequireDigit = false; manager.Options.Password.RequireDigit = false;
manager.Options.Password.RequiredLength = 0; manager.Options.Password.RequiredLength = 0;
IdentityResultAssert.IsFailure(await valid.ValidateAsync(null, input, manager), IdentityResultAssert.IsFailure(await valid.ValidateAsync(manager, null, input),
"Passwords must have at least one non letter and non digit character."); "Passwords must have at least one non letter and non digit character.");
} }
@ -93,7 +93,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Options.Password.RequireLowercase = false; manager.Options.Password.RequireLowercase = false;
manager.Options.Password.RequireDigit = false; manager.Options.Password.RequireDigit = false;
manager.Options.Password.RequiredLength = 0; manager.Options.Password.RequiredLength = 0;
IdentityResultAssert.IsSuccess(await valid.ValidateAsync(null, input, manager)); IdentityResultAssert.IsSuccess(await valid.ValidateAsync(manager, null, input));
} }
[Theory] [Theory]
@ -135,11 +135,11 @@ namespace Microsoft.AspNet.Identity.Test
} }
if (errors.Count == 0) if (errors.Count == 0)
{ {
IdentityResultAssert.IsSuccess(await valid.ValidateAsync(null, input, manager)); IdentityResultAssert.IsSuccess(await valid.ValidateAsync(manager, null, input));
} }
else else
{ {
IdentityResultAssert.IsFailure(await valid.ValidateAsync(null, input, manager), string.Join(" ", errors)); IdentityResultAssert.IsFailure(await valid.ValidateAsync(manager, null, input), string.Join(" ", errors));
} }
} }
} }

View File

@ -2,11 +2,10 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Identity.Test namespace Microsoft.AspNet.Identity.Test
@ -32,11 +31,8 @@ namespace Microsoft.AspNet.Identity.Test
[Fact] [Fact]
public async Task RoleManagerPublicNullChecks() public async Task RoleManagerPublicNullChecks()
{ {
var provider = new ServiceCollection().BuildServiceProvider();
Assert.Throws<ArgumentNullException>("store", Assert.Throws<ArgumentNullException>("store",
() => new RoleManager<TestRole>(null, new RoleValidator<TestRole>())); () => new RoleManager<TestRole>(null, null));
Assert.Throws<ArgumentNullException>("roleValidator",
() => new RoleManager<TestRole>(new NotImplementedStore(), null));
var manager = CreateRoleManager(new NotImplementedStore()); var manager = CreateRoleManager(new NotImplementedStore());
await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.CreateAsync(null)); await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.CreateAsync(null));
await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.UpdateAsync(null)); await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.UpdateAsync(null));
@ -60,7 +56,9 @@ namespace Microsoft.AspNet.Identity.Test
private static RoleManager<TestRole> CreateRoleManager(IRoleStore<TestRole> roleStore) private static RoleManager<TestRole> CreateRoleManager(IRoleStore<TestRole> roleStore)
{ {
return new RoleManager<TestRole>(roleStore, new RoleValidator<TestRole>()); var v = new List<IRoleValidator<TestRole>>();
v.Add(new RoleValidator<TestRole>());
return new RoleManager<TestRole>(roleStore, v);
} }
private class NotImplementedStore : IRoleStore<TestRole> private class NotImplementedStore : IRoleStore<TestRole>

View File

@ -3,8 +3,6 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Identity.Test namespace Microsoft.AspNet.Identity.Test
@ -16,7 +14,7 @@ namespace Microsoft.AspNet.Identity.Test
{ {
// Setup // Setup
var validator = new RoleValidator<TestRole>(); var validator = new RoleValidator<TestRole>();
var manager = new RoleManager<TestRole>(new NoopRoleStore(), validator); var manager = new RoleManager<TestRole>(new NoopRoleStore(), null);
// Act // Act
// Assert // Assert
@ -31,7 +29,7 @@ namespace Microsoft.AspNet.Identity.Test
{ {
// Setup // Setup
var validator = new RoleValidator<TestRole>(); var validator = new RoleValidator<TestRole>();
var manager = new RoleManager<TestRole>(new NoopRoleStore(), validator); var manager = new RoleManager<TestRole>(new NoopRoleStore(), null);
var user = new TestRole {Name = input}; var user = new TestRole {Name = input};
// Act // Act

View File

@ -22,8 +22,8 @@ namespace Microsoft.AspNet.Identity.Test
public IUserStore<TestUser> StorePublic { get { return Store; } } public IUserStore<TestUser> StorePublic { get { return Store; } }
public TestManager(IUserStore<TestUser> store, IOptions<IdentityOptions> optionsAccessor, public TestManager(IUserStore<TestUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TestUser> passwordHasher, IUserValidator<TestUser> userValidator, IPasswordHasher<TestUser> passwordHasher, IEnumerable<IUserValidator<TestUser>> userValidator,
IPasswordValidator<TestUser> passwordValidator) IEnumerable<IPasswordValidator<TestUser>> passwordValidator)
: base(store, optionsAccessor, passwordHasher, userValidator, passwordValidator, null, null, null) { } : base(store, optionsAccessor, passwordHasher, userValidator, passwordValidator, null, null, null) { }
} }
@ -36,8 +36,8 @@ namespace Microsoft.AspNet.Identity.Test
services.AddIdentity<TestUser, IdentityRole>(); services.AddIdentity<TestUser, IdentityRole>();
var manager = services.BuildServiceProvider().GetRequiredService<TestManager>(); var manager = services.BuildServiceProvider().GetRequiredService<TestManager>();
Assert.NotNull(manager.PasswordHasher); Assert.NotNull(manager.PasswordHasher);
Assert.NotNull(manager.PasswordValidator); Assert.Equal(1, manager.PasswordValidators.Count);
Assert.NotNull(manager.UserValidator); Assert.Equal(1, manager.UserValidators.Count);
Assert.NotNull(manager.StorePublic); Assert.NotNull(manager.StorePublic);
Assert.NotNull(manager.Options); Assert.NotNull(manager.Options);
} }
@ -523,7 +523,8 @@ namespace Microsoft.AspNet.Identity.Test
{ {
// TODO: Can switch to Mock eventually // TODO: Can switch to Mock eventually
var manager = MockHelpers.TestUserManager(new EmptyStore()); var manager = MockHelpers.TestUserManager(new EmptyStore());
manager.PasswordValidator = new BadPasswordValidator<TestUser>(); manager.PasswordValidators.Clear();
manager.PasswordValidators.Add(new BadPasswordValidator<TestUser>());
IdentityResultAssert.IsFailure(await manager.CreateAsync(new TestUser(), "password"), IdentityResultAssert.IsFailure(await manager.CreateAsync(new TestUser(), "password"),
BadPasswordValidator<TestUser>.ErrorMessage); BadPasswordValidator<TestUser>.ErrorMessage);
} }
@ -534,8 +535,6 @@ namespace Microsoft.AspNet.Identity.Test
var store = new NotImplementedStore(); var store = new NotImplementedStore();
var optionsAccessor = new OptionsManager<IdentityOptions>(null); var optionsAccessor = new OptionsManager<IdentityOptions>(null);
var passwordHasher = new PasswordHasher<TestUser>(new PasswordHasherOptionsAccessor()); var passwordHasher = new PasswordHasher<TestUser>(new PasswordHasherOptionsAccessor());
var userValidator = new UserValidator<TestUser>();
var passwordValidator = new PasswordValidator<TestUser>();
Assert.Throws<ArgumentNullException>("store", Assert.Throws<ArgumentNullException>("store",
() => new UserManager<TestUser>(null, null, null, null, null, null, null, null)); () => new UserManager<TestUser>(null, null, null, null, null, null, null, null));
@ -544,7 +543,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Throws<ArgumentNullException>("passwordHasher", Assert.Throws<ArgumentNullException>("passwordHasher",
() => new UserManager<TestUser>(store, optionsAccessor, null, null, null, null, null, null)); () => new UserManager<TestUser>(store, optionsAccessor, null, null, null, null, null, null));
var manager = new UserManager<TestUser>(store, optionsAccessor, passwordHasher, userValidator, passwordValidator, null, null, null); var manager = new UserManager<TestUser>(store, optionsAccessor, passwordHasher, null, null, null, null, null);
Assert.Throws<ArgumentNullException>("value", () => manager.PasswordHasher = null); Assert.Throws<ArgumentNullException>("value", () => manager.PasswordHasher = null);
Assert.Throws<ArgumentNullException>("value", () => manager.Options = null); Assert.Throws<ArgumentNullException>("value", () => manager.Options = null);
@ -717,7 +716,7 @@ namespace Microsoft.AspNet.Identity.Test
{ {
public const string ErrorMessage = "I'm Bad."; public const string ErrorMessage = "I'm Bad.";
public Task<IdentityResult> ValidateAsync(TUser user, string password, UserManager<TUser> manager, CancellationToken cancellationToken = default(CancellationToken)) public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password, CancellationToken cancellationToken = default(CancellationToken))
{ {
return Task.FromResult(IdentityResult.Failed(ErrorMessage)); return Task.FromResult(IdentityResult.Failed(ErrorMessage));
} }

View File

@ -4,9 +4,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
using Moq; using Moq;
@ -14,33 +11,20 @@ namespace Microsoft.AspNet.Identity.Test
{ {
public static class MockHelpers public static class MockHelpers
{ {
//public static UserManager<TUser> CreateManager<TUser>(IUserStore<TUser> store) where TUser : class
//{
// var services = new ServiceCollection();
// services.Add(OptionsServices.GetDefaultServices());
// services.Add(HostingServices.GetDefaultServices());
// services.AddDefaultIdentity<TUser, IdentityRole>().AddUserStore(store);
// services.ConfigureIdentity(options =>
// {
// options.Password.RequireDigit = false;
// options.Password.RequireLowercase = false;
// options.Password.RequireNonLetterOrDigit = false;
// options.Password.RequireUppercase = false;
// options.User.UserNameValidationRegex = null;
// });
// return services.BuildServiceProvider().GetService<UserManager<TUser>>();
//}
public static Mock<UserManager<TUser>> MockUserManager<TUser>() where TUser : class public static Mock<UserManager<TUser>> MockUserManager<TUser>() where TUser : class
{ {
var store = new Mock<IUserStore<TUser>>(); var store = new Mock<IUserStore<TUser>>();
var options = new OptionsManager<IdentityOptions>(null); var options = new OptionsManager<IdentityOptions>(null);
var userValidators = new List<IUserValidator<TUser>>();
userValidators.Add(new UserValidator<TUser>());
var pwdValidators = new List<IPasswordValidator<TUser>>();
pwdValidators.Add(new PasswordValidator<TUser>());
return new Mock<UserManager<TUser>>( return new Mock<UserManager<TUser>>(
store.Object, store.Object,
options, options,
new PasswordHasher<TUser>(new PasswordHasherOptionsAccessor()), new PasswordHasher<TUser>(new PasswordHasherOptionsAccessor()),
new UserValidator<TUser>(), userValidators,
new PasswordValidator<TUser>(), pwdValidators,
new UpperInvariantUserNameNormalizer(), new UpperInvariantUserNameNormalizer(),
new List<IUserTokenProvider<TUser>>(), new List<IUserTokenProvider<TUser>>(),
new List<IIdentityMessageProvider>()); new List<IIdentityMessageProvider>());
@ -49,7 +33,9 @@ namespace Microsoft.AspNet.Identity.Test
public static Mock<RoleManager<TRole>> MockRoleManager<TRole>() where TRole : class public static Mock<RoleManager<TRole>> MockRoleManager<TRole>() where TRole : class
{ {
var store = new Mock<IRoleStore<TRole>>(); var store = new Mock<IRoleStore<TRole>>();
return new Mock<RoleManager<TRole>>(store.Object, new RoleValidator<TRole>()); var roles = new List<IRoleValidator<TRole>>();
roles.Add(new RoleValidator<TRole>());
return new Mock<RoleManager<TRole>>(store.Object, roles);
} }
public static UserManager<TUser> TestUserManager<TUser>() where TUser : class public static UserManager<TUser> TestUserManager<TUser>() where TUser : class
@ -62,7 +48,9 @@ namespace Microsoft.AspNet.Identity.Test
var options = new OptionsManager<IdentityOptions>(null); var options = new OptionsManager<IdentityOptions>(null);
var validator = new Mock<UserValidator<TUser>>(); var validator = new Mock<UserValidator<TUser>>();
var userManager = new UserManager<TUser>(store, options, new PasswordHasher<TUser>(new PasswordHasherOptionsAccessor()), var userManager = new UserManager<TUser>(store, options, new PasswordHasher<TUser>(new PasswordHasherOptionsAccessor()),
validator.Object, new PasswordValidator<TUser>(), new UpperInvariantUserNameNormalizer(), null, null); null, null, new UpperInvariantUserNameNormalizer(), null, null);
userManager.UserValidators.Add(validator.Object);
userManager.PasswordValidators.Add(new PasswordValidator<TUser>());
validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<TUser>(), CancellationToken.None)) validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<TUser>(), CancellationToken.None))
.Returns(Task.FromResult(IdentityResult.Success)).Verifiable(); .Returns(Task.FromResult(IdentityResult.Success)).Verifiable();
return userManager; return userManager;

View File

@ -8,9 +8,9 @@ using System.Security.Claims;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Testing; using Microsoft.AspNet.Testing;
using Xunit;
using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback; using Microsoft.Framework.DependencyInjection.Fallback;
using Xunit;
namespace Microsoft.AspNet.Identity.Test namespace Microsoft.AspNet.Identity.Test
{ {
@ -146,7 +146,8 @@ namespace Microsoft.AspNet.Identity.Test
{ {
var manager = CreateManager(); var manager = CreateManager();
var user = CreateTestUser(); var user = CreateTestUser();
manager.UserValidator = new AlwaysBadValidator(); manager.UserValidators.Clear();
manager.UserValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.CreateAsync(user), AlwaysBadValidator.ErrorMessage); IdentityResultAssert.IsFailure(await manager.CreateAsync(user), AlwaysBadValidator.ErrorMessage);
} }
@ -156,10 +157,23 @@ namespace Microsoft.AspNet.Identity.Test
var manager = CreateManager(); var manager = CreateManager();
var user = CreateTestUser(); var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
manager.UserValidator = new AlwaysBadValidator(); manager.UserValidators.Clear();
manager.UserValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.UpdateAsync(user), AlwaysBadValidator.ErrorMessage); IdentityResultAssert.IsFailure(await manager.UpdateAsync(user), AlwaysBadValidator.ErrorMessage);
} }
[Fact]
public async Task CanChainUserValidators()
{
var manager = CreateManager();
manager.UserValidators.Clear();
manager.UserValidators.Add(new AlwaysBadValidator());
manager.UserValidators.Add(new AlwaysBadValidator());
var result = await manager.CreateAsync(CreateTestUser());
IdentityResultAssert.IsFailure(result, AlwaysBadValidator.ErrorMessage);
Assert.Equal(2, result.Errors.Count());
}
[Theory] [Theory]
[InlineData("")] [InlineData("")]
[InlineData(null)] [InlineData(null)]
@ -190,18 +204,34 @@ namespace Microsoft.AspNet.Identity.Test
var manager = CreateManager(); var manager = CreateManager();
var user = CreateTestUser(); var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
manager.PasswordValidator = new AlwaysBadValidator(); manager.PasswordValidators.Clear();
manager.PasswordValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.AddPasswordAsync(user, "password"), IdentityResultAssert.IsFailure(await manager.AddPasswordAsync(user, "password"),
AlwaysBadValidator.ErrorMessage); AlwaysBadValidator.ErrorMessage);
} }
[Fact]
public async Task CanChainPasswordValidators()
{
var manager = CreateManager();
manager.PasswordValidators.Clear();
manager.PasswordValidators.Add(new AlwaysBadValidator());
manager.PasswordValidators.Add(new AlwaysBadValidator());
var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
var result = await manager.AddPasswordAsync(user, "pwd");
IdentityResultAssert.IsFailure(result, AlwaysBadValidator.ErrorMessage);
Assert.Equal(2, result.Errors.Count());
}
[Fact] [Fact]
public async Task PasswordValidatorCanBlockChangePassword() public async Task PasswordValidatorCanBlockChangePassword()
{ {
var manager = CreateManager(); var manager = CreateManager();
var user = CreateTestUser(); var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password")); IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password"));
manager.PasswordValidator = new AlwaysBadValidator(); manager.PasswordValidators.Clear();
manager.PasswordValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.ChangePasswordAsync(user, "password", "new"), IdentityResultAssert.IsFailure(await manager.ChangePasswordAsync(user, "password", "new"),
AlwaysBadValidator.ErrorMessage); AlwaysBadValidator.ErrorMessage);
} }
@ -539,7 +569,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.NotNull(stamp); Assert.NotNull(stamp);
var token = await manager.GeneratePasswordResetTokenAsync(user); var token = await manager.GeneratePasswordResetTokenAsync(user);
Assert.NotNull(token); Assert.NotNull(token);
manager.PasswordValidator = new AlwaysBadValidator(); manager.PasswordValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.ResetPasswordAsync(user, token, newPassword), IdentityResultAssert.IsFailure(await manager.ResetPasswordAsync(user, token, newPassword),
AlwaysBadValidator.ErrorMessage); AlwaysBadValidator.ErrorMessage);
Assert.True(await manager.CheckPasswordAsync(user, password)); Assert.True(await manager.CheckPasswordAsync(user, password));
@ -814,7 +844,7 @@ namespace Microsoft.AspNet.Identity.Test
{ {
public const string ErrorMessage = "I'm Bad."; public const string ErrorMessage = "I'm Bad.";
public Task<IdentityResult> ValidateAsync(TUser user, string password, UserManager<TUser> manager, CancellationToken cancellationToken = default(CancellationToken)) public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password, CancellationToken cancellationToken = default(CancellationToken))
{ {
return Task.FromResult(IdentityResult.Failed(ErrorMessage)); return Task.FromResult(IdentityResult.Failed(ErrorMessage));
} }
@ -834,11 +864,24 @@ namespace Microsoft.AspNet.Identity.Test
public async Task BadValidatorBlocksCreateRole() public async Task BadValidatorBlocksCreateRole()
{ {
var manager = CreateRoleManager(); var manager = CreateRoleManager();
manager.RoleValidator = new AlwaysBadValidator(); manager.RoleValidators.Clear();
manager.RoleValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.CreateAsync(CreateRole("blocked")), IdentityResultAssert.IsFailure(await manager.CreateAsync(CreateRole("blocked")),
AlwaysBadValidator.ErrorMessage); AlwaysBadValidator.ErrorMessage);
} }
[Fact]
public async Task CanChainRoleValidators()
{
var manager = CreateRoleManager();
manager.RoleValidators.Clear();
manager.RoleValidators.Add(new AlwaysBadValidator());
manager.RoleValidators.Add(new AlwaysBadValidator());
var result = await manager.CreateAsync(CreateRole("blocked"));
IdentityResultAssert.IsFailure(result, AlwaysBadValidator.ErrorMessage);
Assert.Equal(2, result.Errors.Count());
}
[Fact] [Fact]
public async Task BadValidatorBlocksRoleUpdate() public async Task BadValidatorBlocksRoleUpdate()
{ {
@ -846,7 +889,8 @@ namespace Microsoft.AspNet.Identity.Test
var role = CreateRole("poorguy"); var role = CreateRole("poorguy");
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role)); IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
var error = AlwaysBadValidator.ErrorMessage; var error = AlwaysBadValidator.ErrorMessage;
manager.RoleValidator = new AlwaysBadValidator(); manager.RoleValidators.Clear();
manager.RoleValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.UpdateAsync(role), error); IdentityResultAssert.IsFailure(await manager.UpdateAsync(role), error);
} }