Introduce SignInResult/IdentityError/Describer
Follows Resource pattern (IdentityErrorDescriber.StringName, or FormatStringName(arg1, arg2) Also cleaned up optional services, by allowing null in constructor SignInStatus -> SignInFailure and introduced SignInResult to make SignInManager APIs consistent with IdentityResult (but no strings needed for SignIn) Fixes: #86, #176, #287 and #177
This commit is contained in:
parent
625b270924
commit
c9d27e27e6
|
|
@ -1,11 +1,10 @@
|
|||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
|
||||
namespace IdentitySample.Models
|
||||
{
|
||||
|
|
@ -43,20 +42,23 @@ namespace IdentitySample.Models
|
|||
ViewBag.ReturnUrl = returnUrl;
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var signInStatus = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
|
||||
switch (signInStatus)
|
||||
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
case SignInStatus.Success:
|
||||
return RedirectToLocal(returnUrl);
|
||||
case SignInStatus.LockedOut:
|
||||
ModelState.AddModelError("", "User is locked out, try again later.");
|
||||
return View(model);
|
||||
case SignInStatus.RequiresVerification:
|
||||
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
|
||||
case SignInStatus.Failure:
|
||||
default:
|
||||
ModelState.AddModelError("", "Invalid username or password.");
|
||||
return View(model);
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
if (result.RequiresTwoFactor)
|
||||
{
|
||||
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelState.AddModelError("", "Invalid username or password.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,22 +145,26 @@ namespace IdentitySample.Models
|
|||
// Sign in the user with this external login provider if the user already has a login
|
||||
var result = await SignInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey,
|
||||
isPersistent: false);
|
||||
switch (result)
|
||||
if (result.Succeeded)
|
||||
{
|
||||
case SignInStatus.Success:
|
||||
return RedirectToLocal(returnUrl);
|
||||
case SignInStatus.LockedOut:
|
||||
return View("Lockout");
|
||||
case SignInStatus.RequiresVerification:
|
||||
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
|
||||
case SignInStatus.Failure:
|
||||
default:
|
||||
// If the user does not have an account, then prompt the user to create an account
|
||||
ViewBag.ReturnUrl = returnUrl;
|
||||
ViewBag.LoginProvider = info.LoginProvider;
|
||||
// REVIEW: handle case where email not in claims?
|
||||
var email = info.ExternalIdentity.FindFirstValue(ClaimTypes.Email);
|
||||
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
|
||||
return RedirectToLocal(returnUrl);
|
||||
}
|
||||
if (result.RequiresTwoFactor)
|
||||
{
|
||||
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the user does not have an account, then prompt the user to create an account
|
||||
ViewBag.ReturnUrl = returnUrl;
|
||||
ViewBag.LoginProvider = info.LoginProvider;
|
||||
// REVIEW: handle case where email not in claims?
|
||||
var email = info.ExternalIdentity.FindFirstValue(ClaimTypes.Email);
|
||||
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,15 +386,18 @@ namespace IdentitySample.Models
|
|||
}
|
||||
|
||||
var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
|
||||
switch (result)
|
||||
if (result.Succeeded)
|
||||
{
|
||||
case SignInStatus.Success:
|
||||
return RedirectToLocal(model.ReturnUrl);
|
||||
case SignInStatus.LockedOut:
|
||||
return View("Lockout");
|
||||
default:
|
||||
ModelState.AddModelError("", "Invalid code.");
|
||||
return View(model);
|
||||
return RedirectToLocal(model.ReturnUrl);
|
||||
}
|
||||
if (result.IsLockedOut)
|
||||
{
|
||||
return View("Lockout");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelState.AddModelError("", "Invalid code.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -398,7 +407,7 @@ namespace IdentitySample.Models
|
|||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError("", error);
|
||||
ModelState.AddModelError("", error.Description);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ namespace IdentitySample
|
|||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError("", error);
|
||||
ModelState.AddModelError("", error.Description);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,12 @@ namespace Microsoft.AspNet.Identity
|
|||
return AddScoped(typeof(IRoleValidator<>).MakeGenericType(RoleType), typeof(T));
|
||||
}
|
||||
|
||||
public IdentityBuilder AddErrorDescriber<TDescriber>() where TDescriber : IdentityErrorDescriber
|
||||
{
|
||||
Services.AddScoped<IdentityErrorDescriber, TDescriber>();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IdentityBuilder AddPasswordValidator<T>() where T : class
|
||||
{
|
||||
return AddScoped(typeof(IPasswordValidator<>).MakeGenericType(UserType), typeof(T));
|
||||
|
|
|
|||
|
|
@ -3,12 +3,9 @@
|
|||
|
||||
namespace Microsoft.AspNet.Identity
|
||||
{
|
||||
public enum SignInStatus
|
||||
public class IdentityError
|
||||
{
|
||||
Success,
|
||||
LockedOut,
|
||||
RequiresVerification,
|
||||
NotAllowed,
|
||||
Failure
|
||||
public string Code { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.Identity
|
||||
{
|
||||
public class IdentityErrorDescriber
|
||||
{
|
||||
public static IdentityErrorDescriber Default = new IdentityErrorDescriber();
|
||||
|
||||
public virtual IdentityError DefaultError()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(DefaultError),
|
||||
Description = Resources.DefaultError
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError PasswordMismatch()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordMismatch),
|
||||
Description = Resources.PasswordMismatch
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError InvalidToken()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidToken),
|
||||
Description = Resources.InvalidToken
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError LoginAlreadyAssociated()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(LoginAlreadyAssociated),
|
||||
Description = Resources.LoginAlreadyAssociated
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError InvalidUserName(string name)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidUserName),
|
||||
Description = Resources.FormatInvalidUserName(name)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError InvalidEmail(string email)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidEmail),
|
||||
Description = Resources.FormatInvalidEmail(email)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError DuplicateUserName(string name)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(DuplicateUserName),
|
||||
Description = Resources.FormatDuplicateUserName(name)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError DuplicateEmail(string email)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(DuplicateEmail),
|
||||
Description = Resources.FormatDuplicateEmail(email)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError InvalidRoleName(string name)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidRoleName),
|
||||
Description = Resources.FormatInvalidRoleName(name)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError DuplicateRoleName(string name)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(DuplicateRoleName),
|
||||
Description = Resources.FormatDuplicateRoleName(name)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError UserAlreadyHasPassword()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(UserAlreadyHasPassword),
|
||||
Description = Resources.UserAlreadyHasPassword
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError UserLockoutNotEnabled()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(UserLockoutNotEnabled),
|
||||
Description = Resources.UserLockoutNotEnabled
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError UserAlreadyInRole(string role)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(UserAlreadyInRole),
|
||||
Description = Resources.FormatUserAlreadyInRole(role)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError UserNotInRole(string role)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(UserNotInRole),
|
||||
Description = Resources.FormatUserNotInRole(role)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError PasswordTooShort(int length)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordTooShort),
|
||||
Description = Resources.FormatPasswordTooShort(length)
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError PasswordRequiresNonLetterAndDigit()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresNonLetterAndDigit),
|
||||
Description = Resources.PasswordRequiresNonLetterAndDigit
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError PasswordRequiresDigit()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresDigit),
|
||||
Description = Resources.PasswordRequiresDigit
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError PasswordRequiresLower()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresLower),
|
||||
Description = Resources.PasswordRequiresLower
|
||||
};
|
||||
}
|
||||
|
||||
public virtual IdentityError PasswordRequiresUpper()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresUpper),
|
||||
Description = Resources.PasswordRequiresUpper
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,45 +11,19 @@ namespace Microsoft.AspNet.Identity
|
|||
/// </summary>
|
||||
public class IdentityResult
|
||||
{
|
||||
private static readonly IdentityResult _success = new IdentityResult(true);
|
||||
private static readonly IdentityResult _success = new IdentityResult { Succeeded = true };
|
||||
|
||||
/// <summary>
|
||||
/// Failure constructor that takes error messages
|
||||
/// </summary>
|
||||
/// <param name="errors"></param>
|
||||
public IdentityResult(params string[] errors) : this((IEnumerable<string>)errors)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Failure constructor that takes error messages
|
||||
/// </summary>
|
||||
/// <param name="errors"></param>
|
||||
public IdentityResult(IEnumerable<string> errors)
|
||||
{
|
||||
if (errors == null || !errors.Any())
|
||||
{
|
||||
errors = new[] { Resources.DefaultError };
|
||||
}
|
||||
Succeeded = false;
|
||||
Errors = errors;
|
||||
}
|
||||
|
||||
protected IdentityResult(bool success)
|
||||
{
|
||||
Succeeded = success;
|
||||
Errors = new string[0];
|
||||
}
|
||||
private List<IdentityError> _errors = new List<IdentityError>();
|
||||
|
||||
/// <summary>
|
||||
/// True if the operation was successful
|
||||
/// </summary>
|
||||
public bool Succeeded { get; private set; }
|
||||
public bool Succeeded { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of errors
|
||||
/// </summary>
|
||||
public IEnumerable<string> Errors { get; private set; }
|
||||
public IEnumerable<IdentityError> Errors { get { return _errors; } }
|
||||
|
||||
/// <summary>
|
||||
/// Static success result
|
||||
|
|
@ -65,9 +39,14 @@ namespace Microsoft.AspNet.Identity
|
|||
/// </summary>
|
||||
/// <param name="errors"></param>
|
||||
/// <returns></returns>
|
||||
public static IdentityResult Failed(params string[] errors)
|
||||
public static IdentityResult Failed(params IdentityError[] errors)
|
||||
{
|
||||
return new IdentityResult(errors);
|
||||
var result = new IdentityResult { Succeeded = false };
|
||||
if (errors != null)
|
||||
{
|
||||
result._errors.AddRange(errors);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,6 +59,8 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
services.TryAdd(describe.Transient<IPasswordHasher<TUser>, PasswordHasher<TUser>>());
|
||||
services.TryAdd(describe.Transient<IUserNameNormalizer, UpperInvariantUserNameNormalizer>());
|
||||
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>());
|
||||
services.TryAdd(describe.Scoped<ISecurityStampValidator, SecurityStampValidator<TUser>>());
|
||||
services.TryAdd(describe.Scoped<IClaimsIdentityFactory<TUser>, ClaimsIdentityFactory<TUser, TRole>>());
|
||||
services.TryAdd(describe.Scoped<UserManager<TUser>, UserManager<TUser>>());
|
||||
|
|
|
|||
|
|
@ -37,14 +37,11 @@ namespace Microsoft.AspNet.Identity
|
|||
/// Constructs a PasswordHasher using the specified options
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public PasswordHasher(IOptions<PasswordHasherOptions> options)
|
||||
public PasswordHasher(IOptions<PasswordHasherOptions> optionsAccessor = null)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
var options = optionsAccessor?.Options ?? new PasswordHasherOptions();
|
||||
|
||||
_compatibilityMode = options.Options.CompatibilityMode;
|
||||
_compatibilityMode = options.CompatibilityMode;
|
||||
switch (_compatibilityMode)
|
||||
{
|
||||
case PasswordHasherCompatibilityMode.IdentityV2:
|
||||
|
|
@ -52,7 +49,7 @@ namespace Microsoft.AspNet.Identity
|
|||
break;
|
||||
|
||||
case PasswordHasherCompatibilityMode.IdentityV3:
|
||||
_iterCount = options.Options.IterationCount;
|
||||
_iterCount = options.IterationCount;
|
||||
if (_iterCount < 1)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.InvalidPasswordHasherIterationCount);
|
||||
|
|
@ -63,7 +60,7 @@ namespace Microsoft.AspNet.Identity
|
|||
throw new InvalidOperationException(Resources.InvalidPasswordHasherCompatibilityMode);
|
||||
}
|
||||
|
||||
_rng = options.Options.Rng;
|
||||
_rng = options.Rng;
|
||||
}
|
||||
|
||||
// Compares two byte arrays for equality. The method is specifically written so that the loop is not optimized.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -15,6 +14,13 @@ namespace Microsoft.AspNet.Identity
|
|||
/// </summary>
|
||||
public class PasswordValidator<TUser> : IPasswordValidator<TUser> where TUser : class
|
||||
{
|
||||
public PasswordValidator(IdentityErrorDescriber errors = null)
|
||||
{
|
||||
Describer = errors ?? new IdentityErrorDescriber();
|
||||
}
|
||||
|
||||
public IdentityErrorDescriber Describer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the password is of the required length and meets the configured requirements
|
||||
/// </summary>
|
||||
|
|
@ -33,33 +39,32 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
throw new ArgumentNullException("manager");
|
||||
}
|
||||
var errors = new List<string>();
|
||||
var errors = new List<IdentityError>();
|
||||
var options = manager.Options.Password;
|
||||
if (string.IsNullOrWhiteSpace(password) || password.Length < options.RequiredLength)
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PasswordTooShort,
|
||||
options.RequiredLength));
|
||||
errors.Add(Describer.PasswordTooShort(options.RequiredLength));
|
||||
}
|
||||
if (options.RequireNonLetterOrDigit && password.All(IsLetterOrDigit))
|
||||
{
|
||||
errors.Add(Resources.PasswordRequireNonLetterOrDigit);
|
||||
errors.Add(Describer.PasswordRequiresNonLetterAndDigit());
|
||||
}
|
||||
if (options.RequireDigit && !password.Any(IsDigit))
|
||||
{
|
||||
errors.Add(Resources.PasswordRequireDigit);
|
||||
errors.Add(Describer.PasswordRequiresDigit());
|
||||
}
|
||||
if (options.RequireLowercase && !password.Any(IsLower))
|
||||
{
|
||||
errors.Add(Resources.PasswordRequireLower);
|
||||
errors.Add(Describer.PasswordRequiresLower());
|
||||
}
|
||||
if (options.RequireUppercase && !password.Any(IsUpper))
|
||||
{
|
||||
errors.Add(Resources.PasswordRequireUpper);
|
||||
errors.Add(Describer.PasswordRequiresUpper());
|
||||
}
|
||||
return
|
||||
Task.FromResult(errors.Count == 0
|
||||
? IdentityResult.Success
|
||||
: IdentityResult.Failed(String.Join(" ", errors)));
|
||||
: IdentityResult.Failed(errors.ToArray()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -139,35 +139,35 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name {0} is already taken.
|
||||
/// Role Name '{0}' is already taken.
|
||||
/// </summary>
|
||||
internal static string DuplicateName
|
||||
internal static string DuplicateRoleName
|
||||
{
|
||||
get { return GetString("DuplicateName"); }
|
||||
get { return GetString("DuplicateRoleName"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name {0} is already taken.
|
||||
/// Role Name '{0}' is already taken.
|
||||
/// </summary>
|
||||
internal static string FormatDuplicateName(object p0)
|
||||
internal static string FormatDuplicateRoleName(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateName"), p0);
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateRoleName"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A user with that external login already exists.
|
||||
/// UserName '{0}' is already taken.
|
||||
/// </summary>
|
||||
internal static string ExternalLoginExists
|
||||
internal static string DuplicateUserName
|
||||
{
|
||||
get { return GetString("ExternalLoginExists"); }
|
||||
get { return GetString("DuplicateUserName"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A user with that external login already exists.
|
||||
/// UserName '{0}' is already taken.
|
||||
/// </summary>
|
||||
internal static string FormatExternalLoginExists()
|
||||
internal static string FormatDuplicateUserName(object p0)
|
||||
{
|
||||
return GetString("ExternalLoginExists");
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateUserName"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -218,6 +218,22 @@ namespace Microsoft.AspNet.Identity
|
|||
return GetString("InvalidPasswordHasherIterationCount");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Role name '{0}' is invalid.
|
||||
/// </summary>
|
||||
internal static string InvalidRoleName
|
||||
{
|
||||
get { return GetString("InvalidRoleName"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Role name '{0}' is invalid.
|
||||
/// </summary>
|
||||
internal static string FormatInvalidRoleName(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidRoleName"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalid token.
|
||||
/// </summary>
|
||||
|
|
@ -235,7 +251,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// User name {0} is invalid, can only contain letters or digits.
|
||||
/// User name '{0}' is invalid, can only contain letters or digits.
|
||||
/// </summary>
|
||||
internal static string InvalidUserName
|
||||
{
|
||||
|
|
@ -243,7 +259,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// User name {0} is invalid, can only contain letters or digits.
|
||||
/// User name '{0}' is invalid, can only contain letters or digits.
|
||||
/// </summary>
|
||||
internal static string FormatInvalidUserName(object p0)
|
||||
{
|
||||
|
|
@ -251,19 +267,19 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lockout is not enabled for this user.
|
||||
/// A user with this login already exists.
|
||||
/// </summary>
|
||||
internal static string LockoutNotEnabled
|
||||
internal static string LoginAlreadyAssociated
|
||||
{
|
||||
get { return GetString("LockoutNotEnabled"); }
|
||||
get { return GetString("LoginAlreadyAssociated"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lockout is not enabled for this user.
|
||||
/// A user with this login already exists.
|
||||
/// </summary>
|
||||
internal static string FormatLockoutNotEnabled()
|
||||
internal static string FormatLoginAlreadyAssociated()
|
||||
{
|
||||
return GetString("LockoutNotEnabled");
|
||||
return GetString("LoginAlreadyAssociated");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -317,65 +333,65 @@ namespace Microsoft.AspNet.Identity
|
|||
/// <summary>
|
||||
/// Passwords must have at least one digit ('0'-'9').
|
||||
/// </summary>
|
||||
internal static string PasswordRequireDigit
|
||||
internal static string PasswordRequiresDigit
|
||||
{
|
||||
get { return GetString("PasswordRequireDigit"); }
|
||||
get { return GetString("PasswordRequiresDigit"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Passwords must have at least one digit ('0'-'9').
|
||||
/// </summary>
|
||||
internal static string FormatPasswordRequireDigit()
|
||||
internal static string FormatPasswordRequiresDigit()
|
||||
{
|
||||
return GetString("PasswordRequireDigit");
|
||||
return GetString("PasswordRequiresDigit");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Passwords must have at least one lowercase ('a'-'z').
|
||||
/// </summary>
|
||||
internal static string PasswordRequireLower
|
||||
internal static string PasswordRequiresLower
|
||||
{
|
||||
get { return GetString("PasswordRequireLower"); }
|
||||
get { return GetString("PasswordRequiresLower"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Passwords must have at least one lowercase ('a'-'z').
|
||||
/// </summary>
|
||||
internal static string FormatPasswordRequireLower()
|
||||
internal static string FormatPasswordRequiresLower()
|
||||
{
|
||||
return GetString("PasswordRequireLower");
|
||||
return GetString("PasswordRequiresLower");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Passwords must have at least one non letter and non digit character.
|
||||
/// </summary>
|
||||
internal static string PasswordRequireNonLetterOrDigit
|
||||
internal static string PasswordRequiresNonLetterAndDigit
|
||||
{
|
||||
get { return GetString("PasswordRequireNonLetterOrDigit"); }
|
||||
get { return GetString("PasswordRequiresNonLetterAndDigit"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Passwords must have at least one non letter and non digit character.
|
||||
/// </summary>
|
||||
internal static string FormatPasswordRequireNonLetterOrDigit()
|
||||
internal static string FormatPasswordRequiresNonLetterAndDigit()
|
||||
{
|
||||
return GetString("PasswordRequireNonLetterOrDigit");
|
||||
return GetString("PasswordRequiresNonLetterAndDigit");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Passwords must have at least one uppercase ('A'-'Z').
|
||||
/// </summary>
|
||||
internal static string PasswordRequireUpper
|
||||
internal static string PasswordRequiresUpper
|
||||
{
|
||||
get { return GetString("PasswordRequireUpper"); }
|
||||
get { return GetString("PasswordRequiresUpper"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Passwords must have at least one uppercase ('A'-'Z').
|
||||
/// </summary>
|
||||
internal static string FormatPasswordRequireUpper()
|
||||
internal static string FormatPasswordRequiresUpper()
|
||||
{
|
||||
return GetString("PasswordRequireUpper");
|
||||
return GetString("PasswordRequiresUpper");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -651,7 +667,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// User already in role.
|
||||
/// User already in role '{0}'.
|
||||
/// </summary>
|
||||
internal static string UserAlreadyInRole
|
||||
{
|
||||
|
|
@ -659,11 +675,43 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// User already in role.
|
||||
/// User already in role '{0}'.
|
||||
/// </summary>
|
||||
internal static string FormatUserAlreadyInRole()
|
||||
internal static string FormatUserAlreadyInRole(object p0)
|
||||
{
|
||||
return GetString("UserAlreadyInRole");
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("UserAlreadyInRole"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User is locked out.
|
||||
/// </summary>
|
||||
internal static string UserLockedOut
|
||||
{
|
||||
get { return GetString("UserLockedOut"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User is locked out.
|
||||
/// </summary>
|
||||
internal static string FormatUserLockedOut()
|
||||
{
|
||||
return GetString("UserLockedOut");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lockout is not enabled for this user.
|
||||
/// </summary>
|
||||
internal static string UserLockoutNotEnabled
|
||||
{
|
||||
get { return GetString("UserLockoutNotEnabled"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lockout is not enabled for this user.
|
||||
/// </summary>
|
||||
internal static string FormatUserLockoutNotEnabled()
|
||||
{
|
||||
return GetString("UserLockoutNotEnabled");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -683,7 +731,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// User is not in role.
|
||||
/// User is not in role '{0}'.
|
||||
/// </summary>
|
||||
internal static string UserNotInRole
|
||||
{
|
||||
|
|
@ -691,11 +739,11 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// User is not in role.
|
||||
/// User is not in role '{0}'.
|
||||
/// </summary>
|
||||
internal static string FormatUserNotInRole()
|
||||
internal static string FormatUserNotInRole(object p0)
|
||||
{
|
||||
return GetString("UserNotInRole");
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("UserNotInRole"), p0);
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
|
|
|
|||
|
|
@ -149,13 +149,13 @@
|
|||
<value>Email '{0}' is already taken.</value>
|
||||
<comment>error for duplicate emails</comment>
|
||||
</data>
|
||||
<data name="DuplicateName" xml:space="preserve">
|
||||
<value>Name {0} is already taken.</value>
|
||||
<data name="DuplicateRoleName" xml:space="preserve">
|
||||
<value>Role Name '{0}' is already taken.</value>
|
||||
<comment>error for duplicate usernames</comment>
|
||||
</data>
|
||||
<data name="ExternalLoginExists" xml:space="preserve">
|
||||
<value>A user with that external login already exists.</value>
|
||||
<comment>Error when a login already linked</comment>
|
||||
<data name="DuplicateUserName" xml:space="preserve">
|
||||
<value>UserName '{0}' is already taken.</value>
|
||||
<comment>error for duplicate usernames</comment>
|
||||
</data>
|
||||
<data name="InvalidEmail" xml:space="preserve">
|
||||
<value>Email '{0}' is invalid.</value>
|
||||
|
|
@ -169,17 +169,21 @@
|
|||
<value>The iteration count must be a positive integer.</value>
|
||||
<comment>Error when the iteration count is < 1.</comment>
|
||||
</data>
|
||||
<data name="InvalidRoleName" xml:space="preserve">
|
||||
<value>Role name '{0}' is invalid.</value>
|
||||
<comment>error for invalid role names</comment>
|
||||
</data>
|
||||
<data name="InvalidToken" xml:space="preserve">
|
||||
<value>Invalid token.</value>
|
||||
<comment>Error when a token is not recognized</comment>
|
||||
</data>
|
||||
<data name="InvalidUserName" xml:space="preserve">
|
||||
<value>User name {0} is invalid, can only contain letters or digits.</value>
|
||||
<value>User name '{0}' is invalid, can only contain letters or digits.</value>
|
||||
<comment>usernames can only contain letters or digits</comment>
|
||||
</data>
|
||||
<data name="LockoutNotEnabled" xml:space="preserve">
|
||||
<value>Lockout is not enabled for this user.</value>
|
||||
<comment>error when lockout is not enabled</comment>
|
||||
<data name="LoginAlreadyAssociated" xml:space="preserve">
|
||||
<value>A user with this login already exists.</value>
|
||||
<comment>Error when a login already linked</comment>
|
||||
</data>
|
||||
<data name="NoMessageProvider" xml:space="preserve">
|
||||
<value>No IUserMessageProvider named '{0}' is registered.</value>
|
||||
|
|
@ -193,19 +197,19 @@
|
|||
<value>Incorrect password.</value>
|
||||
<comment>Error when a password doesn't match</comment>
|
||||
</data>
|
||||
<data name="PasswordRequireDigit" xml:space="preserve">
|
||||
<data name="PasswordRequiresDigit" xml:space="preserve">
|
||||
<value>Passwords must have at least one digit ('0'-'9').</value>
|
||||
<comment>Error when passwords do not have a digit</comment>
|
||||
</data>
|
||||
<data name="PasswordRequireLower" xml:space="preserve">
|
||||
<data name="PasswordRequiresLower" xml:space="preserve">
|
||||
<value>Passwords must have at least one lowercase ('a'-'z').</value>
|
||||
<comment>Error when passwords do not have a lowercase letter</comment>
|
||||
</data>
|
||||
<data name="PasswordRequireNonLetterOrDigit" xml:space="preserve">
|
||||
<data name="PasswordRequiresNonLetterAndDigit" xml:space="preserve">
|
||||
<value>Passwords must have at least one non letter and non digit character.</value>
|
||||
<comment>Error when password does not have enough letter or digit characters</comment>
|
||||
</data>
|
||||
<data name="PasswordRequireUpper" xml:space="preserve">
|
||||
<data name="PasswordRequiresUpper" xml:space="preserve">
|
||||
<value>Passwords must have at least one uppercase ('A'-'Z').</value>
|
||||
<comment>Error when passwords do not have an uppercase letter</comment>
|
||||
</data>
|
||||
|
|
@ -213,10 +217,6 @@
|
|||
<value>Passwords must be at least {0} characters.</value>
|
||||
<comment>Error message for passwords that are too short</comment>
|
||||
</data>
|
||||
<data name="PropertyTooShort" xml:space="preserve">
|
||||
<value>{0} cannot be null or empty.</value>
|
||||
<comment>error for empty or null usernames</comment>
|
||||
</data>
|
||||
<data name="RoleNotFound" xml:space="preserve">
|
||||
<value>Role {0} does not exist.</value>
|
||||
<comment>error when a role does not exist</comment>
|
||||
|
|
@ -278,15 +278,23 @@
|
|||
<comment>error when AddPasswordAsync called when a user already has a password</comment>
|
||||
</data>
|
||||
<data name="UserAlreadyInRole" xml:space="preserve">
|
||||
<value>User already in role.</value>
|
||||
<value>User already in role '{0}'.</value>
|
||||
<comment>Error when a user is already in a role</comment>
|
||||
</data>
|
||||
<data name="UserLockedOut" xml:space="preserve">
|
||||
<value>User is locked out.</value>
|
||||
<comment>Error when a user is locked out</comment>
|
||||
</data>
|
||||
<data name="UserLockoutNotEnabled" xml:space="preserve">
|
||||
<value>Lockout is not enabled for this user.</value>
|
||||
<comment>error when lockout is not enabled</comment>
|
||||
</data>
|
||||
<data name="UserNameNotFound" xml:space="preserve">
|
||||
<value>User {0} does not exist.</value>
|
||||
<comment>error when a user does not exist</comment>
|
||||
</data>
|
||||
<data name="UserNotInRole" xml:space="preserve">
|
||||
<value>User is not in role.</value>
|
||||
<value>User is not in role '{0}'.</value>
|
||||
<comment>Error when a user is not in the role</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -24,13 +24,16 @@ namespace Microsoft.AspNet.Identity
|
|||
/// </summary>
|
||||
/// <param name="store">The IRoleStore commits changes via the UpdateAsync/CreateAsync methods</param>
|
||||
/// <param name="roleValidator"></param>
|
||||
public RoleManager(IRoleStore<TRole> store, IEnumerable<IRoleValidator<TRole>> roleValidators)
|
||||
public RoleManager(IRoleStore<TRole> store,
|
||||
IEnumerable<IRoleValidator<TRole>> roleValidators = null,
|
||||
IdentityErrorDescriber errors = null)
|
||||
{
|
||||
if (store == null)
|
||||
{
|
||||
throw new ArgumentNullException("store");
|
||||
}
|
||||
Store = store;
|
||||
ErrorDescriber = errors ?? new IdentityErrorDescriber();
|
||||
|
||||
if (roleValidators != null)
|
||||
{
|
||||
|
|
@ -51,6 +54,11 @@ namespace Microsoft.AspNet.Identity
|
|||
/// </summary>
|
||||
public IList<IRoleValidator<TRole>> RoleValidators { get; } = new List<IRoleValidator<TRole>>();
|
||||
|
||||
/// <summary>
|
||||
/// Used to generate public API error messages
|
||||
/// </summary>
|
||||
public IdentityErrorDescriber ErrorDescriber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns an IQueryable of roles if the store is an IQueryableRoleStore
|
||||
/// </summary>
|
||||
|
|
@ -102,7 +110,7 @@ namespace Microsoft.AspNet.Identity
|
|||
|
||||
private async Task<IdentityResult> ValidateRoleInternal(TRole role, CancellationToken cancellationToken)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
var errors = new List<IdentityError>();
|
||||
foreach (var v in RoleValidators)
|
||||
{
|
||||
var result = await v.ValidateAsync(this, role, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -15,6 +14,13 @@ namespace Microsoft.AspNet.Identity
|
|||
/// <typeparam name="TRole"></typeparam>
|
||||
public class RoleValidator<TRole> : IRoleValidator<TRole> where TRole : class
|
||||
{
|
||||
public RoleValidator(IdentityErrorDescriber errors = null)
|
||||
{
|
||||
Describer = errors ?? new IdentityErrorDescriber();
|
||||
}
|
||||
|
||||
private IdentityErrorDescriber Describer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Validates a role before saving
|
||||
/// </summary>
|
||||
|
|
@ -33,7 +39,7 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
throw new ArgumentNullException("role");
|
||||
}
|
||||
var errors = new List<string>();
|
||||
var errors = new List<IdentityError>();
|
||||
await ValidateRoleName(manager, role, errors);
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
|
|
@ -42,13 +48,13 @@ namespace Microsoft.AspNet.Identity
|
|||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
private static async Task ValidateRoleName(RoleManager<TRole> manager, TRole role,
|
||||
ICollection<string> errors)
|
||||
private async Task ValidateRoleName(RoleManager<TRole> manager, TRole role,
|
||||
ICollection<IdentityError> errors)
|
||||
{
|
||||
var roleName = await manager.GetRoleNameAsync(role);
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "Name"));
|
||||
errors.Add(Describer.InvalidRoleName(roleName));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -56,7 +62,7 @@ namespace Microsoft.AspNet.Identity
|
|||
if (owner != null &&
|
||||
!string.Equals(await manager.GetRoleIdAsync(owner), await manager.GetRoleIdAsync(role)))
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateName, roleName));
|
||||
errors.Add(Describer.DuplicateRoleName(roleName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ namespace Microsoft.AspNet.Identity
|
|||
/// <typeparam name="TUser"></typeparam>
|
||||
public class SignInManager<TUser> where TUser : class
|
||||
{
|
||||
public SignInManager(UserManager<TUser> userManager, IContextAccessor<HttpContext> contextAccessor,
|
||||
IClaimsIdentityFactory<TUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor)
|
||||
public SignInManager(UserManager<TUser> userManager,
|
||||
IContextAccessor<HttpContext> contextAccessor,
|
||||
IClaimsIdentityFactory<TUser> claimsFactory,
|
||||
IOptions<IdentityOptions> optionsAccessor = null)
|
||||
{
|
||||
if (userManager == null)
|
||||
{
|
||||
|
|
@ -36,14 +38,10 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
throw new ArgumentNullException(nameof(claimsFactory));
|
||||
}
|
||||
if (optionsAccessor == null || optionsAccessor.Options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(optionsAccessor));
|
||||
}
|
||||
UserManager = userManager;
|
||||
Context = contextAccessor.Value;
|
||||
ClaimsFactory = claimsFactory;
|
||||
Options = optionsAccessor.Options;
|
||||
Options = optionsAccessor?.Options ?? new IdentityOptions();
|
||||
}
|
||||
|
||||
public UserManager<TUser> UserManager { get; private set; }
|
||||
|
|
@ -96,15 +94,15 @@ namespace Microsoft.AspNet.Identity
|
|||
return UserManager.SupportsUserLockout && await UserManager.IsLockedOutAsync(user, token);
|
||||
}
|
||||
|
||||
private async Task<SignInStatus?> PreSignInCheck(TUser user, CancellationToken token)
|
||||
private async Task<SignInResult> PreSignInCheck(TUser user, CancellationToken token)
|
||||
{
|
||||
if (!await CanSignInAsync(user, token))
|
||||
{
|
||||
return SignInStatus.NotAllowed;
|
||||
return SignInResult.NotAllowed;
|
||||
}
|
||||
if (await IsLockedOut(user, token))
|
||||
{
|
||||
return SignInStatus.LockedOut;
|
||||
return SignInResult.LockedOut;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -141,13 +139,21 @@ namespace Microsoft.AspNet.Identity
|
|||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task<SignInStatus> PasswordSignInAsync(TUser user, string password,
|
||||
public virtual async Task<SignInResult> PasswordSignInAsync(TUser user, string password,
|
||||
bool isPersistent, bool shouldLockout, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
var error = await PreSignInCheck(user, cancellationToken);
|
||||
if (error != null)
|
||||
{
|
||||
return error.Value;
|
||||
return error;
|
||||
}
|
||||
if (await IsLockedOut(user, cancellationToken))
|
||||
{
|
||||
return SignInResult.LockedOut;
|
||||
}
|
||||
if (await UserManager.CheckPasswordAsync(user, password, cancellationToken))
|
||||
{
|
||||
|
|
@ -160,19 +166,19 @@ namespace Microsoft.AspNet.Identity
|
|||
await UserManager.AccessFailedAsync(user, cancellationToken);
|
||||
if (await UserManager.IsLockedOutAsync(user, cancellationToken))
|
||||
{
|
||||
return SignInStatus.LockedOut;
|
||||
return SignInResult.LockedOut;
|
||||
}
|
||||
}
|
||||
return SignInStatus.Failure;
|
||||
return SignInResult.Failed;
|
||||
}
|
||||
|
||||
public virtual async Task<SignInStatus> PasswordSignInAsync(string userName, string password,
|
||||
public virtual async Task<SignInResult> PasswordSignInAsync(string userName, string password,
|
||||
bool isPersistent, bool shouldLockout, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(userName, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return SignInStatus.Failure;
|
||||
return SignInResult.Failed;
|
||||
}
|
||||
return await PasswordSignInAsync(user, password, isPersistent, shouldLockout, cancellationToken);
|
||||
}
|
||||
|
|
@ -207,7 +213,6 @@ namespace Microsoft.AspNet.Identity
|
|||
return false;
|
||||
}
|
||||
var token = await UserManager.GenerateTwoFactorTokenAsync(user, provider, cancellationToken);
|
||||
// See IdentityConfig.cs to plug in Email/SMS services to actually send the code
|
||||
await UserManager.NotifyTwoFactorTokenAsync(user, provider, token, cancellationToken);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -236,23 +241,23 @@ namespace Microsoft.AspNet.Identity
|
|||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public virtual async Task<SignInStatus> TwoFactorSignInAsync(string provider, string code, bool isPersistent,
|
||||
public virtual async Task<SignInResult> TwoFactorSignInAsync(string provider, string code, bool isPersistent,
|
||||
bool rememberClient, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var twoFactorInfo = await RetrieveTwoFactorInfoAsync(cancellationToken);
|
||||
if (twoFactorInfo == null || twoFactorInfo.UserId == null)
|
||||
{
|
||||
return SignInStatus.Failure;
|
||||
return SignInResult.Failed;
|
||||
}
|
||||
var user = await UserManager.FindByIdAsync(twoFactorInfo.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return SignInStatus.Failure;
|
||||
return SignInResult.Failed;
|
||||
}
|
||||
var error = await PreSignInCheck(user, cancellationToken);
|
||||
if (error != null)
|
||||
{
|
||||
return error.Value;
|
||||
return error;
|
||||
}
|
||||
if (await UserManager.VerifyTwoFactorTokenAsync(user, provider, code, cancellationToken))
|
||||
{
|
||||
|
|
@ -268,11 +273,13 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
await RememberTwoFactorClientAsync(user, cancellationToken);
|
||||
}
|
||||
return SignInStatus.Success;
|
||||
await UserManager.ResetAccessFailedCountAsync(user, cancellationToken);
|
||||
await SignInAsync(user, isPersistent);
|
||||
return SignInResult.Success;
|
||||
}
|
||||
// If the token is incorrect, record the failure which also may cause the user to be locked out
|
||||
await UserManager.AccessFailedAsync(user, cancellationToken);
|
||||
return SignInStatus.Failure;
|
||||
return SignInResult.Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -292,18 +299,18 @@ namespace Microsoft.AspNet.Identity
|
|||
return await UserManager.FindByIdAsync(info.UserId, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<SignInStatus> ExternalLoginSignInAsync(string loginProvider, string providerKey, bool isPersistent,
|
||||
public async Task<SignInResult> ExternalLoginSignInAsync(string loginProvider, string providerKey, bool isPersistent,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var user = await UserManager.FindByLoginAsync(loginProvider, providerKey, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return SignInStatus.Failure;
|
||||
return SignInResult.Failed;
|
||||
}
|
||||
var error = await PreSignInCheck(user, cancellationToken);
|
||||
if (error != null)
|
||||
{
|
||||
return error.Value;
|
||||
return error;
|
||||
}
|
||||
return await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken, loginProvider);
|
||||
}
|
||||
|
|
@ -358,7 +365,7 @@ namespace Microsoft.AspNet.Identity
|
|||
return properties;
|
||||
}
|
||||
|
||||
private async Task<SignInStatus> SignInOrTwoFactorAsync(TUser user, bool isPersistent,
|
||||
private async Task<SignInResult> SignInOrTwoFactorAsync(TUser user, bool isPersistent,
|
||||
CancellationToken cancellationToken, string loginProvider = null)
|
||||
{
|
||||
if (UserManager.SupportsUserTwoFactor &&
|
||||
|
|
@ -370,7 +377,7 @@ namespace Microsoft.AspNet.Identity
|
|||
// Store the userId for use after two factor check
|
||||
var userId = await UserManager.GetUserIdAsync(user, cancellationToken);
|
||||
Context.Response.SignIn(StoreTwoFactorInfo(userId, loginProvider));
|
||||
return SignInStatus.RequiresVerification;
|
||||
return SignInResult.TwoFactorRequired;
|
||||
}
|
||||
}
|
||||
// Cleanup external cookie
|
||||
|
|
@ -379,7 +386,7 @@ namespace Microsoft.AspNet.Identity
|
|||
Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationType);
|
||||
}
|
||||
await SignInAsync(user, isPersistent, loginProvider, cancellationToken);
|
||||
return SignInStatus.Success;
|
||||
return SignInResult.Success;
|
||||
}
|
||||
|
||||
private async Task<TwoFactorAuthenticationInfo> RetrieveTwoFactorInfoAsync(CancellationToken cancellationToken)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the result of an sign in operation
|
||||
/// </summary>
|
||||
public class SignInResult
|
||||
{
|
||||
private static readonly SignInResult _success = new SignInResult { Succeeded = true };
|
||||
private static readonly SignInResult _failed = new SignInResult();
|
||||
private static readonly SignInResult _lockedOut = new SignInResult { IsLockedOut = true };
|
||||
private static readonly SignInResult _notAllowed = new SignInResult { IsNotAllowed = true };
|
||||
private static readonly SignInResult _twoFactorRequired = new SignInResult { RequiresTwoFactor = true };
|
||||
|
||||
/// <summary>
|
||||
/// True if the operation was successful
|
||||
/// </summary>
|
||||
public bool Succeeded { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the user is locked out
|
||||
/// </summary>
|
||||
public bool IsLockedOut { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the user is not allowed to sign in
|
||||
/// </summary>
|
||||
public bool IsNotAllowed { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the sign in requires two factor
|
||||
/// </summary>
|
||||
public bool RequiresTwoFactor { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Static success result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static SignInResult Success
|
||||
{
|
||||
get { return _success; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static failure result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static SignInResult Failed
|
||||
{
|
||||
get { return _failed; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static locked out result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static SignInResult LockedOut
|
||||
{
|
||||
get { return _lockedOut; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static not allowed result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static SignInResult NotAllowed
|
||||
{
|
||||
get { return _notAllowed; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static two factor required result
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static SignInResult TwoFactorRequired
|
||||
{
|
||||
get { return _twoFactorRequired; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -39,30 +39,24 @@ namespace Microsoft.AspNet.Identity
|
|||
/// <param name="passwordValidator"></param>
|
||||
/// <param name="claimsIdentityFactory"></param>
|
||||
public UserManager(IUserStore<TUser> store,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
IPasswordHasher<TUser> passwordHasher,
|
||||
IEnumerable<IUserValidator<TUser>> userValidators,
|
||||
IEnumerable<IPasswordValidator<TUser>> passwordValidators,
|
||||
IUserNameNormalizer userNameNormalizer,
|
||||
IEnumerable<IUserTokenProvider<TUser>> tokenProviders,
|
||||
IEnumerable<IIdentityMessageProvider> msgProviders)
|
||||
IOptions<IdentityOptions> optionsAccessor = null,
|
||||
IPasswordHasher<TUser> passwordHasher = null,
|
||||
IEnumerable<IUserValidator<TUser>> userValidators = null,
|
||||
IEnumerable<IPasswordValidator<TUser>> passwordValidators = null,
|
||||
IUserNameNormalizer userNameNormalizer = null,
|
||||
IdentityErrorDescriber errors = null,
|
||||
IEnumerable<IUserTokenProvider<TUser>> tokenProviders = null,
|
||||
IEnumerable<IIdentityMessageProvider> msgProviders = null)
|
||||
{
|
||||
if (store == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(store));
|
||||
}
|
||||
if (optionsAccessor == null || optionsAccessor.Options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(optionsAccessor));
|
||||
}
|
||||
if (passwordHasher == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(passwordHasher));
|
||||
}
|
||||
Store = store;
|
||||
Options = optionsAccessor.Options;
|
||||
PasswordHasher = passwordHasher;
|
||||
UserNameNormalizer = userNameNormalizer;
|
||||
Options = optionsAccessor?.Options ?? new IdentityOptions();
|
||||
PasswordHasher = passwordHasher ?? new PasswordHasher<TUser>();
|
||||
UserNameNormalizer = userNameNormalizer ?? new UpperInvariantUserNameNormalizer();
|
||||
ErrorDescriber = errors ?? new IdentityErrorDescriber();
|
||||
if (userValidators != null)
|
||||
{
|
||||
foreach (var v in userValidators)
|
||||
|
|
@ -136,6 +130,11 @@ namespace Microsoft.AspNet.Identity
|
|||
/// </summary>
|
||||
public IUserNameNormalizer UserNameNormalizer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to generate public API error messages
|
||||
/// </summary>
|
||||
public IdentityErrorDescriber ErrorDescriber { get; set; }
|
||||
|
||||
public IdentityOptions Options
|
||||
{
|
||||
get
|
||||
|
|
@ -301,7 +300,7 @@ namespace Microsoft.AspNet.Identity
|
|||
|
||||
private async Task<IdentityResult> ValidateUserInternal(TUser user, CancellationToken cancellationToken)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
var errors = new List<IdentityError>();
|
||||
foreach (var v in UserValidators)
|
||||
{
|
||||
var result = await v.ValidateAsync(this, user, cancellationToken);
|
||||
|
|
@ -315,7 +314,7 @@ namespace Microsoft.AspNet.Identity
|
|||
|
||||
private async Task<IdentityResult> ValidatePasswordInternal(TUser user, string password, CancellationToken cancellationToken)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
var errors = new List<IdentityError>();
|
||||
foreach (var v in PasswordValidators)
|
||||
{
|
||||
var result = await v.ValidateAsync(this, user, password, cancellationToken);
|
||||
|
|
@ -598,7 +597,7 @@ namespace Microsoft.AspNet.Identity
|
|||
var hash = await passwordStore.GetPasswordHashAsync(user, cancellationToken);
|
||||
if (hash != null)
|
||||
{
|
||||
return new IdentityResult(Resources.UserAlreadyHasPassword);
|
||||
return IdentityResult.Failed(ErrorDescriber.UserAlreadyHasPassword());
|
||||
}
|
||||
var result = await UpdatePasswordInternal(passwordStore, user, password, cancellationToken);
|
||||
if (!result.Succeeded)
|
||||
|
|
@ -634,7 +633,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
return await UpdateAsync(user, cancellationToken);
|
||||
}
|
||||
return IdentityResult.Failed(Resources.PasswordMismatch);
|
||||
return IdentityResult.Failed(ErrorDescriber.PasswordMismatch());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -766,7 +765,7 @@ namespace Microsoft.AspNet.Identity
|
|||
// Make sure the token is valid and the stamp matches
|
||||
if (!await VerifyUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword", token, cancellationToken))
|
||||
{
|
||||
return IdentityResult.Failed(Resources.InvalidToken);
|
||||
return IdentityResult.Failed(ErrorDescriber.InvalidToken());
|
||||
}
|
||||
var passwordStore = GetPasswordStore();
|
||||
var result = await UpdatePasswordInternal(passwordStore, user, newPassword, cancellationToken);
|
||||
|
|
@ -877,7 +876,7 @@ namespace Microsoft.AspNet.Identity
|
|||
var existingUser = await FindByLoginAsync(login.LoginProvider, login.ProviderKey, cancellationToken);
|
||||
if (existingUser != null)
|
||||
{
|
||||
return IdentityResult.Failed(Resources.ExternalLoginExists);
|
||||
return IdentityResult.Failed(ErrorDescriber.LoginAlreadyAssociated());
|
||||
}
|
||||
await loginStore.AddLoginAsync(user, login, cancellationToken);
|
||||
return await UpdateAsync(user, cancellationToken);
|
||||
|
|
@ -1082,7 +1081,7 @@ namespace Microsoft.AspNet.Identity
|
|||
var userRoles = await userRoleStore.GetRolesAsync(user, cancellationToken);
|
||||
if (userRoles.Contains(role))
|
||||
{
|
||||
return new IdentityResult(Resources.UserAlreadyInRole);
|
||||
return IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role));
|
||||
}
|
||||
await userRoleStore.AddToRoleAsync(user, role, cancellationToken);
|
||||
return await UpdateAsync(user, cancellationToken);
|
||||
|
|
@ -1113,7 +1112,7 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
if (userRoles.Contains(role))
|
||||
{
|
||||
return new IdentityResult(Resources.UserAlreadyInRole);
|
||||
return IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role));
|
||||
}
|
||||
await userRoleStore.AddToRoleAsync(user, role, cancellationToken);
|
||||
}
|
||||
|
|
@ -1138,7 +1137,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
if (!await userRoleStore.IsInRoleAsync(user, role, cancellationToken))
|
||||
{
|
||||
return new IdentityResult(Resources.UserNotInRole);
|
||||
return IdentityResult.Failed(ErrorDescriber.UserNotInRole(role));
|
||||
}
|
||||
await userRoleStore.RemoveFromRoleAsync(user, role, cancellationToken);
|
||||
return await UpdateAsync(user, cancellationToken);
|
||||
|
|
@ -1168,7 +1167,7 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
if (!await userRoleStore.IsInRoleAsync(user, role, cancellationToken))
|
||||
{
|
||||
return new IdentityResult(Resources.UserNotInRole);
|
||||
return IdentityResult.Failed(ErrorDescriber.UserNotInRole(role));
|
||||
}
|
||||
await userRoleStore.RemoveFromRoleAsync(user, role, cancellationToken);
|
||||
}
|
||||
|
|
@ -1313,7 +1312,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
if (!await VerifyUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "Confirmation", token, cancellationToken))
|
||||
{
|
||||
return IdentityResult.Failed(Resources.InvalidToken);
|
||||
return IdentityResult.Failed(ErrorDescriber.InvalidToken());
|
||||
}
|
||||
await store.SetEmailConfirmedAsync(user, true, cancellationToken);
|
||||
return await UpdateAsync(user, cancellationToken);
|
||||
|
|
@ -1374,7 +1373,7 @@ namespace Microsoft.AspNet.Identity
|
|||
// Make sure the token is valid and the stamp matches
|
||||
if (!await VerifyUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail), token, cancellationToken))
|
||||
{
|
||||
return IdentityResult.Failed(Resources.InvalidToken);
|
||||
return IdentityResult.Failed(ErrorDescriber.InvalidToken());
|
||||
}
|
||||
var store = GetEmailStore();
|
||||
await store.SetEmailAsync(user, newEmail, cancellationToken);
|
||||
|
|
@ -1453,7 +1452,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
if (!await VerifyChangePhoneNumberTokenAsync(user, token, phoneNumber, cancellationToken))
|
||||
{
|
||||
return IdentityResult.Failed(Resources.InvalidToken);
|
||||
return IdentityResult.Failed(ErrorDescriber.InvalidToken());
|
||||
}
|
||||
await store.SetPhoneNumberAsync(user, phoneNumber, cancellationToken);
|
||||
await store.SetPhoneNumberConfirmedAsync(user, true, cancellationToken);
|
||||
|
|
@ -1890,7 +1889,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
if (!await store.GetLockoutEnabledAsync(user, cancellationToken).ConfigureAwait((false)))
|
||||
{
|
||||
return IdentityResult.Failed(Resources.LockoutNotEnabled);
|
||||
return IdentityResult.Failed(ErrorDescriber.UserLockoutNotEnabled());
|
||||
}
|
||||
await store.SetLockoutEndDateAsync(user, lockoutEnd, cancellationToken);
|
||||
return await UpdateAsync(user, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
#if ASPNET50
|
||||
using System.Net.Mail;
|
||||
#endif
|
||||
|
|
@ -19,6 +18,13 @@ namespace Microsoft.AspNet.Identity
|
|||
/// <typeparam name="TUser"></typeparam>
|
||||
public class UserValidator<TUser> : IUserValidator<TUser> where TUser : class
|
||||
{
|
||||
public UserValidator(IdentityErrorDescriber errors = null)
|
||||
{
|
||||
Describer = errors ?? new IdentityErrorDescriber();
|
||||
}
|
||||
|
||||
public IdentityErrorDescriber Describer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Validates a user before saving
|
||||
/// </summary>
|
||||
|
|
@ -37,7 +43,7 @@ namespace Microsoft.AspNet.Identity
|
|||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
var errors = new List<string>();
|
||||
var errors = new List<IdentityError>();
|
||||
await ValidateUserName(manager, user, errors);
|
||||
if (manager.Options.User.RequireUniqueEmail)
|
||||
{
|
||||
|
|
@ -46,16 +52,16 @@ namespace Microsoft.AspNet.Identity
|
|||
return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
|
||||
}
|
||||
|
||||
private async Task ValidateUserName(UserManager<TUser> manager, TUser user, ICollection<string> errors)
|
||||
private async Task ValidateUserName(UserManager<TUser> manager, TUser user, ICollection<IdentityError> errors)
|
||||
{
|
||||
var userName = await manager.GetUserNameAsync(user);
|
||||
if (string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "UserName"));
|
||||
errors.Add(Describer.InvalidUserName(userName));
|
||||
}
|
||||
else if (manager.Options.User.UserNameValidationRegex != null && !Regex.IsMatch(userName, manager.Options.User.UserNameValidationRegex))
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.InvalidUserName, userName));
|
||||
errors.Add(Describer.InvalidUserName(userName));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -63,18 +69,18 @@ namespace Microsoft.AspNet.Identity
|
|||
if (owner != null &&
|
||||
!string.Equals(await manager.GetUserIdAsync(owner), await manager.GetUserIdAsync(user)))
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateName, userName));
|
||||
errors.Add(Describer.DuplicateUserName(userName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure email is not empty, valid, and unique
|
||||
private static async Task ValidateEmail(UserManager<TUser> manager, TUser user, List<string> errors)
|
||||
private async Task ValidateEmail(UserManager<TUser> manager, TUser user, List<IdentityError> errors)
|
||||
{
|
||||
var email = await manager.GetEmailAsync(user);
|
||||
if (string.IsNullOrWhiteSpace(email))
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "Email"));
|
||||
errors.Add(Describer.InvalidEmail(email));
|
||||
return;
|
||||
}
|
||||
#if ASPNET50
|
||||
|
|
@ -84,7 +90,7 @@ namespace Microsoft.AspNet.Identity
|
|||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.InvalidEmail, email));
|
||||
errors.Add(Describer.InvalidEmail(email));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -92,7 +98,7 @@ namespace Microsoft.AspNet.Identity
|
|||
if (owner != null &&
|
||||
!string.Equals(await manager.GetUserIdAsync(owner), await manager.GetUserIdAsync(user)))
|
||||
{
|
||||
errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateEmail, email));
|
||||
errors.Add(Describer.DuplicateEmail(email));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ namespace Microsoft.AspNet.Identity.InMemory.Test
|
|||
var signInManager = app.ApplicationServices.GetRequiredService<SignInManager<ApplicationUser>>();
|
||||
|
||||
IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user, password));
|
||||
var result = await signInManager.PasswordSignInAsync(user.UserName, password, isPersistent, false);
|
||||
var result = await signInManager.PasswordSignInAsync(user, password, isPersistent, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.Success, result);
|
||||
Assert.True(result.Succeeded);
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
contextAccessor.VerifyAll();
|
||||
|
|
|
|||
|
|
@ -226,18 +226,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
|
||||
private class MyUserManager : UserManager<TestUser>
|
||||
{
|
||||
public MyUserManager(IUserStore<TestUser> store,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
IPasswordHasher<TestUser> passwordHasher,
|
||||
IEnumerable<IUserValidator<TestUser>> userValidators,
|
||||
IEnumerable<IPasswordValidator<TestUser>> passwordValidators,
|
||||
IUserNameNormalizer userNameNormalizer,
|
||||
IEnumerable<IUserTokenProvider<TestUser>> tokenProviders,
|
||||
IEnumerable<IIdentityMessageProvider> msgProviders) :
|
||||
base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, userNameNormalizer, tokenProviders, msgProviders)
|
||||
{
|
||||
|
||||
}
|
||||
public MyUserManager(IUserStore<TestUser> store) : base(store) { }
|
||||
}
|
||||
|
||||
private class MyRoleManager : RoleManager<TestRole>
|
||||
|
|
|
|||
|
|
@ -13,17 +13,15 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
{
|
||||
var result = new IdentityResult();
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal(1, result.Errors.Count());
|
||||
Assert.Equal("An unknown failure has occured.", result.Errors.First());
|
||||
Assert.Equal(0, result.Errors.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NullErrorListUsesDefaultError()
|
||||
public void NullFailedUsesEmptyErrors()
|
||||
{
|
||||
var result = new IdentityResult(null);
|
||||
var result = IdentityResult.Failed();
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal(1, result.Errors.Count());
|
||||
Assert.Equal("An unknown failure has occured.", result.Errors.First());
|
||||
Assert.Equal(0, result.Errors.Count());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -133,13 +134,18 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
{
|
||||
errors.Add(upperError);
|
||||
}
|
||||
var result = await valid.ValidateAsync(manager, null, input);
|
||||
if (errors.Count == 0)
|
||||
{
|
||||
IdentityResultAssert.IsSuccess(await valid.ValidateAsync(manager, null, input));
|
||||
IdentityResultAssert.IsSuccess(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
IdentityResultAssert.IsFailure(await valid.ValidateAsync(manager, null, input), string.Join(" ", errors));
|
||||
IdentityResultAssert.IsFailure(result);
|
||||
foreach (var error in errors)
|
||||
{
|
||||
Assert.True(result.Errors.Any(e => e.Description == error));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await validator.ValidateAsync(manager, user);
|
||||
|
||||
// Assert
|
||||
IdentityResultAssert.IsFailure(result, "Name cannot be null or empty.");
|
||||
IdentityResultAssert.IsFailure(result, IdentityErrorDescriber.Default.InvalidRoleName(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Security;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Security;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Identity.Test
|
||||
|
|
@ -75,8 +75,6 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var context = new Mock<HttpContext>();
|
||||
contextAccessor.Setup(a => a.Value).Returns(context.Object);
|
||||
Assert.Throws<ArgumentNullException>("claimsFactory", () => new SignInManager<IdentityUser>(userManager, contextAccessor.Object, null, null));
|
||||
var claimsFactory = new Mock<IClaimsIdentityFactory<IdentityUser>>().Object;
|
||||
Assert.Throws<ArgumentNullException>("optionsAccessor", () => new SignInManager<IdentityUser>(userManager, contextAccessor.Object, claimsFactory, null));
|
||||
}
|
||||
|
||||
//TODO: Mock fails in K (this works fine in net45)
|
||||
|
|
@ -132,7 +130,8 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.LockedOut, result);
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.True(result.IsLockedOut);
|
||||
manager.VerifyAll();
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +166,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user.UserName, "password", isPersistent, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.Success, result);
|
||||
Assert.True(result.Succeeded);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
|
|
@ -203,7 +202,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.Success, result);
|
||||
Assert.True(result.Succeeded);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
|
|
@ -251,7 +250,8 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.RequiresVerification, result);
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.True(result.RequiresTwoFactor);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
|
|
@ -297,7 +297,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.ExternalLoginSignInAsync(loginProvider, providerKey, isPersistent);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.Success, result);
|
||||
Assert.True(result.Succeeded);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
|
|
@ -382,7 +382,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.TwoFactorSignInAsync(provider, code, isPersistent, rememberClient);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.Success, result);
|
||||
Assert.True(result.Succeeded);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
|
|
@ -466,7 +466,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user.UserName, "password", isPersistent, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.Success, result);
|
||||
Assert.True(result.Succeeded);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
|
|
@ -530,7 +530,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.Failure, result);
|
||||
Assert.False(result.Succeeded);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
contextAccessor.VerifyAll();
|
||||
|
|
@ -556,7 +556,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync("bogus", "bogus", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.Failure, result);
|
||||
Assert.False(result.Succeeded);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
contextAccessor.VerifyAll();
|
||||
|
|
@ -592,7 +592,8 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, true);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(SignInStatus.LockedOut, result);
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.True(result.IsLockedOut);
|
||||
manager.VerifyAll();
|
||||
}
|
||||
|
||||
|
|
@ -631,7 +632,9 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(confirmed ? SignInStatus.Success : SignInStatus.NotAllowed, result);
|
||||
|
||||
Assert.Equal(confirmed, result.Succeeded);
|
||||
Assert.NotEqual(confirmed, result.IsNotAllowed);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
|
|
@ -670,7 +673,8 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await helper.PasswordSignInAsync(user, "password", false, false);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(confirmed ? SignInStatus.Success : SignInStatus.NotAllowed, result);
|
||||
Assert.Equal(confirmed, result.Succeeded);
|
||||
Assert.NotEqual(confirmed, result.IsNotAllowed);
|
||||
manager.VerifyAll();
|
||||
context.VerifyAll();
|
||||
response.VerifyAll();
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.DependencyInjection.Fallback;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.DependencyInjection.Fallback;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Identity.Test
|
||||
|
|
@ -21,10 +20,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
{
|
||||
public IUserStore<TestUser> StorePublic { get { return Store; } }
|
||||
|
||||
public TestManager(IUserStore<TestUser> store, IOptions<IdentityOptions> optionsAccessor,
|
||||
IPasswordHasher<TestUser> passwordHasher, IEnumerable<IUserValidator<TestUser>> userValidator,
|
||||
IEnumerable<IPasswordValidator<TestUser>> passwordValidator)
|
||||
: base(store, optionsAccessor, passwordHasher, userValidator, passwordValidator, null, null, null) { }
|
||||
public TestManager(IUserStore<TestUser> store) : base(store) { }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -36,8 +32,6 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
services.AddIdentity<TestUser, IdentityRole>();
|
||||
var manager = services.BuildServiceProvider().GetRequiredService<TestManager>();
|
||||
Assert.NotNull(manager.PasswordHasher);
|
||||
Assert.Equal(1, manager.PasswordValidators.Count);
|
||||
Assert.Equal(1, manager.UserValidators.Count);
|
||||
Assert.NotNull(manager.StorePublic);
|
||||
Assert.NotNull(manager.Options);
|
||||
}
|
||||
|
|
@ -66,7 +60,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var store = new Mock<IUserStore<TestUser>>();
|
||||
var user = new TestUser { UserName = "Foo" };
|
||||
store.Setup(s => s.DeleteAsync(user, CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
|
||||
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
|
||||
var userManager = MockHelpers.TestUserManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await userManager.DeleteAsync(user);
|
||||
|
|
@ -100,7 +94,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
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();
|
||||
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
|
||||
var userManager = MockHelpers.TestUserManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await userManager.SetUserNameAsync(user, "foo");
|
||||
|
|
@ -207,7 +201,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await userManager.AddToRolesAsync(user, roles);
|
||||
|
||||
// Assert
|
||||
IdentityResultAssert.IsFailure(result, "User already in role.");
|
||||
IdentityResultAssert.IsFailure(result, IdentityErrorDescriber.Default.UserAlreadyInRole("B"));
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
|
|
@ -269,7 +263,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await userManager.RemoveFromRolesAsync(user, roles);
|
||||
|
||||
// Assert
|
||||
IdentityResultAssert.IsFailure(result, "User is not in role.");
|
||||
IdentityResultAssert.IsFailure(result, IdentityErrorDescriber.Default.UserNotInRole("B"));
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +278,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
.Returns(Task.FromResult(0))
|
||||
.Verifiable();
|
||||
store.Setup(s => s.UpdateAsync(user, CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
|
||||
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
|
||||
var userManager = MockHelpers.TestUserManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await userManager.AddClaimsAsync(user, claims);
|
||||
|
|
@ -305,7 +299,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
.Returns(Task.FromResult(0))
|
||||
.Verifiable();
|
||||
store.Setup(s => s.UpdateAsync(user, CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
|
||||
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
|
||||
var userManager = MockHelpers.TestUserManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await userManager.AddClaimAsync(user, claim);
|
||||
|
|
@ -326,7 +320,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
store.Setup(s => s.ReplaceClaimAsync(user, It.IsAny<Claim>(), It.IsAny<Claim>(), CancellationToken.None))
|
||||
.Returns(Task.FromResult(0))
|
||||
.Verifiable();
|
||||
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
|
||||
var userManager = MockHelpers.TestUserManager(store.Object);
|
||||
|
||||
// Act
|
||||
var result = await userManager.ReplaceClaimAsync(user, claim, newClaim);
|
||||
|
|
@ -533,17 +527,11 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
public async Task ManagerPublicNullChecks()
|
||||
{
|
||||
var store = new NotImplementedStore();
|
||||
var optionsAccessor = new OptionsManager<IdentityOptions>(null);
|
||||
var passwordHasher = new PasswordHasher<TestUser>(new PasswordHasherOptionsAccessor());
|
||||
|
||||
Assert.Throws<ArgumentNullException>("store",
|
||||
() => new UserManager<TestUser>(null, null, null, null, null, null, null, null));
|
||||
Assert.Throws<ArgumentNullException>("optionsAccessor",
|
||||
() => new UserManager<TestUser>(store, null, null, null, null, null, null, null));
|
||||
Assert.Throws<ArgumentNullException>("passwordHasher",
|
||||
() => new UserManager<TestUser>(store, optionsAccessor, null, null, null, null, null, null));
|
||||
() => new UserManager<TestUser>(null));
|
||||
|
||||
var manager = new UserManager<TestUser>(store, optionsAccessor, passwordHasher, null, null, null, null, null);
|
||||
var manager = new UserManager<TestUser>(store);
|
||||
|
||||
Assert.Throws<ArgumentNullException>("value", () => manager.PasswordHasher = null);
|
||||
Assert.Throws<ArgumentNullException>("value", () => manager.Options = null);
|
||||
|
|
@ -714,7 +702,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
|
||||
private class BadPasswordValidator<TUser> : IPasswordValidator<TUser> where TUser : class
|
||||
{
|
||||
public const string ErrorMessage = "I'm Bad.";
|
||||
public static readonly IdentityError ErrorMessage = new IdentityError { Description = "I'm Bad." };
|
||||
|
||||
public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
|
|
@ -1239,5 +1227,51 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanCustomizeUserValidatorErrors()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
var store = new Mock<IUserEmailStore<TestUser>>();
|
||||
var describer = new TestErrorDescriber();
|
||||
services.AddInstance<IdentityErrorDescriber>(describer)
|
||||
.AddInstance<IUserStore<TestUser>>(store.Object)
|
||||
.AddIdentity<TestUser, IdentityRole>();
|
||||
|
||||
var manager = services.BuildServiceProvider().GetRequiredService<UserManager<TestUser>>();
|
||||
|
||||
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))
|
||||
.Returns(Task.FromResult(user2))
|
||||
.Verifiable();
|
||||
store.Setup(s => s.GetUserIdAsync(user2, CancellationToken.None))
|
||||
.Returns(Task.FromResult(user2.Id))
|
||||
.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();
|
||||
|
||||
Assert.Same(describer, manager.ErrorDescriber);
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user), describer.DuplicateEmail(user.Email));
|
||||
|
||||
store.VerifyAll();
|
||||
}
|
||||
|
||||
public class TestErrorDescriber : IdentityErrorDescriber
|
||||
{
|
||||
public static string Code = "Error";
|
||||
public static string FormatError = "FormatError {0}";
|
||||
|
||||
public override IdentityError DuplicateEmail(string email)
|
||||
{
|
||||
return new IdentityError { Code = Code, Description = string.Format(FormatError, email) };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var result = await validator.ValidateAsync(manager, user);
|
||||
|
||||
// Assert
|
||||
IdentityResultAssert.IsFailure(result, "UserName cannot be null or empty.");
|
||||
IdentityResultAssert.IsFailure(result, IdentityErrorDescriber.Default.InvalidUserName(input));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
|
|||
|
|
@ -24,7 +24,16 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
{
|
||||
Assert.NotNull(result);
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal(error, result.Errors.First());
|
||||
Assert.Equal(error, result.Errors.First().Description);
|
||||
}
|
||||
|
||||
public static void IsFailure(IdentityResult result, IdentityError error)
|
||||
{
|
||||
Assert.NotNull(result);
|
||||
Assert.False(result.Succeeded);
|
||||
Assert.Equal(error.Description, result.Errors.First().Description);
|
||||
Assert.Equal(error.Code, result.Errors.First().Code);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -14,20 +14,10 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
public static Mock<UserManager<TUser>> MockUserManager<TUser>() where TUser : class
|
||||
{
|
||||
var store = new Mock<IUserStore<TUser>>();
|
||||
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>>(
|
||||
store.Object,
|
||||
options,
|
||||
new PasswordHasher<TUser>(new PasswordHasherOptionsAccessor()),
|
||||
userValidators,
|
||||
pwdValidators,
|
||||
new UpperInvariantUserNameNormalizer(),
|
||||
new List<IUserTokenProvider<TUser>>(),
|
||||
new List<IIdentityMessageProvider>());
|
||||
var mgr = new Mock<UserManager<TUser>>(store.Object, null, null, null, null, null, null, null, null);
|
||||
mgr.Object.UserValidators.Add(new UserValidator<TUser>());
|
||||
mgr.Object.PasswordValidators.Add(new PasswordValidator<TUser>());
|
||||
return mgr;
|
||||
}
|
||||
|
||||
public static Mock<RoleManager<TRole>> MockRoleManager<TRole>() where TRole : class
|
||||
|
|
@ -35,7 +25,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var store = new Mock<IRoleStore<TRole>>();
|
||||
var roles = new List<IRoleValidator<TRole>>();
|
||||
roles.Add(new RoleValidator<TRole>());
|
||||
return new Mock<RoleManager<TRole>>(store.Object, roles);
|
||||
return new Mock<RoleManager<TRole>>(store.Object, roles, null);
|
||||
}
|
||||
|
||||
public static UserManager<TUser> TestUserManager<TUser>() where TUser : class
|
||||
|
|
@ -45,10 +35,8 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
|
||||
public static UserManager<TUser> TestUserManager<TUser>(IUserStore<TUser> store) where TUser : class
|
||||
{
|
||||
var options = new OptionsManager<IdentityOptions>(null);
|
||||
var validator = new Mock<UserValidator<TUser>>();
|
||||
var userManager = new UserManager<TUser>(store, options, new PasswordHasher<TUser>(new PasswordHasherOptionsAccessor()),
|
||||
null, null, new UpperInvariantUserNameNormalizer(), null, null);
|
||||
var validator = new Mock<IUserValidator<TUser>>();
|
||||
var userManager = new UserManager<TUser>(store);
|
||||
userManager.UserValidators.Add(validator.Object);
|
||||
userManager.PasswordValidators.Add(new PasswordValidator<TUser>());
|
||||
validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<TUser>(), CancellationToken.None))
|
||||
|
|
|
|||
|
|
@ -14,5 +14,6 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
|
||||
public string Id { get; private set; }
|
||||
public string UserName { get; set; }
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -182,7 +182,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var manager = CreateManager();
|
||||
var user = CreateTestUser();
|
||||
manager.Options.User.RequireUniqueEmail = true;
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user), "Email cannot be null or empty.");
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user), IdentityErrorDescriber.Default.InvalidEmail(email));
|
||||
}
|
||||
|
||||
#if ASPNET50
|
||||
|
|
@ -194,7 +194,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var manager = CreateManager();
|
||||
var user = new TUser() { UserName = "UpdateBlocked", Email = email };
|
||||
manager.Options.User.RequireUniqueEmail = true;
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user), "Email '" + email + "' is invalid.");
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user), IdentityErrorDescriber.Default.InvalidEmail(email));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -414,7 +414,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
var user = CreateTestUser();
|
||||
var user2 = new TUser() { UserName = user.UserName };
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user2), "Name "+user.UserName+" is already taken.");
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user2), IdentityErrorDescriber.Default.DuplicateUserName(user.UserName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -440,7 +440,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
user.Email = email;
|
||||
user2.Email = email;
|
||||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user2), "Email '"+email+"' is already taken.");
|
||||
IdentityResultAssert.IsFailure(await manager.CreateAsync(user2), IdentityErrorDescriber.Default.DuplicateEmail(user.Email));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -465,7 +465,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login));
|
||||
var result = await manager.AddLoginAsync(user, login);
|
||||
IdentityResultAssert.IsFailure(result, "A user with that external login already exists.");
|
||||
IdentityResultAssert.IsFailure(result, IdentityErrorDescriber.Default.LoginAlreadyAssociated());
|
||||
}
|
||||
|
||||
// Email tests
|
||||
|
|
@ -842,7 +842,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
private class AlwaysBadValidator : IUserValidator<TUser>, IRoleValidator<TRole>,
|
||||
IPasswordValidator<TUser>
|
||||
{
|
||||
public const string ErrorMessage = "I'm Bad.";
|
||||
public static readonly IdentityError ErrorMessage = new IdentityError { Description = "I'm Bad." };
|
||||
|
||||
public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
|
|
@ -1142,7 +1142,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
var result = await userMgr.RemoveFromRoleAsync(user, role.Name);
|
||||
IdentityResultAssert.IsFailure(result, "User is not in role.");
|
||||
IdentityResultAssert.IsFailure(result, IdentityErrorDescriber.Default.UserNotInRole(role.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1157,7 +1157,7 @@ namespace Microsoft.AspNet.Identity.Test
|
|||
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
|
||||
IdentityResultAssert.IsSuccess(await userMgr.AddToRoleAsync(user, role.Name));
|
||||
Assert.True(await userMgr.IsInRoleAsync(user, role.Name));
|
||||
IdentityResultAssert.IsFailure(await userMgr.AddToRoleAsync(user, role.Name), "User already in role.");
|
||||
IdentityResultAssert.IsFailure(await userMgr.AddToRoleAsync(user, role.Name), IdentityErrorDescriber.Default.UserAlreadyInRole(role.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in New Issue