Added logging to code and updated tests

This commit is contained in:
Suhas Joshi 2014-11-19 16:23:20 -08:00
parent 69ac9abcc5
commit 6e294035a5
26 changed files with 975 additions and 202 deletions

View File

@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Identity
{
@ -48,5 +49,23 @@ namespace Microsoft.AspNet.Identity
}
return result;
}
/// <summary>
/// Log Identity result
/// </summary>
/// <param name="logger"></param>
/// <param name="message"></param>
public virtual void Log(ILogger logger, string message)
{
// TODO: Take logging level as a parameter
if (Succeeded)
{
logger.WriteInformation(Resources.FormatLogIdentityResultSuccess(message));
}
else
{
logger.WriteWarning(Resources.FormatLogIdentityResultFailure(message, string.Join(",", Errors.Select(x => x.Code).ToList())));
}
}
}
}

View File

@ -13,6 +13,9 @@
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
<ProjectExtensions>
<VisualStudio>

View File

@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// Security Code
/// Security code
/// </summary>
internal static string DefaultEmailTokenProviderSubject
{
@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// Security Code
/// Security code
/// </summary>
internal static string FormatDefaultEmailTokenProviderSubject()
{
@ -123,7 +123,7 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// DefaultTokenProvider
/// Default Token Provider
/// </summary>
internal static string DefaultTokenProvider
{
@ -131,7 +131,7 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// DefaultTokenProvider
/// Default Token Provider
/// </summary>
internal static string FormatDefaultTokenProvider()
{
@ -155,7 +155,7 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// Role Name '{0}' is already taken.
/// Role name '{0}' is already taken.
/// </summary>
internal static string DuplicateRoleName
{
@ -163,7 +163,7 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// Role Name '{0}' is already taken.
/// Role name '{0}' is already taken.
/// </summary>
internal static string FormatDuplicateRoleName(object p0)
{
@ -171,7 +171,7 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// UserName '{0}' is already taken.
/// User name '{0}' is already taken.
/// </summary>
internal static string DuplicateUserName
{
@ -179,7 +179,7 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// UserName '{0}' is already taken.
/// User name '{0}' is already taken.
/// </summary>
internal static string FormatDuplicateUserName(object p0)
{
@ -746,6 +746,86 @@ namespace Microsoft.AspNet.Identity
return string.Format(CultureInfo.CurrentCulture, GetString("UserNotInRole"), p0);
}
/// <summary>
/// {0} : Failed : {1}
/// </summary>
internal static string LogIdentityResultFailure
{
get { return GetString("LogIdentityResultFailure"); }
}
/// <summary>
/// {0} : Failed : {1}
/// </summary>
internal static string FormatLogIdentityResultFailure(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("LogIdentityResultFailure"), p0, p1);
}
/// <summary>
/// {0} : Success
/// </summary>
internal static string LogIdentityResultSuccess
{
get { return GetString("LogIdentityResultSuccess"); }
}
/// <summary>
/// {0} : Success
/// </summary>
internal static string FormatLogIdentityResultSuccess(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("LogIdentityResultSuccess"), p0);
}
/// <summary>
/// {0} : Result : {1}
/// </summary>
internal static string LoggingSigninResult
{
get { return GetString("LoggingSigninResult"); }
}
/// <summary>
/// {0} : Result : {1}
/// </summary>
internal static string FormatLoggingSigninResult(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("LoggingSigninResult"), p0, p1);
}
/// <summary>
/// {0} for user: {1}
/// </summary>
internal static string LoggingResultMessage
{
get { return GetString("LoggingResultMessage"); }
}
/// <summary>
/// {0} for user: {1}
/// </summary>
internal static string FormatLoggingResultMessage(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("LoggingResultMessage"), p0, p1);
}
/// <summary>
/// {0} for role: {1}
/// </summary>
internal static string LoggingResultMessageForRole
{
get { return GetString("LoggingResultMessageForRole"); }
}
/// <summary>
/// {0} for role: {1}
/// </summary>
internal static string FormatLoggingResultMessageForRole(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("LoggingResultMessageForRole"), p0, p1);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -130,7 +130,7 @@
<comment>Default name for the email token provider</comment>
</data>
<data name="DefaultEmailTokenProviderSubject" xml:space="preserve">
<value>Security Code</value>
<value>Security code</value>
<comment>Default subject for the email</comment>
</data>
<data name="DefaultError" xml:space="preserve">
@ -146,24 +146,24 @@
<comment>Default name for the phone number token provider</comment>
</data>
<data name="DefaultTokenProvider" xml:space="preserve">
<value>DefaultTokenProvider</value>
<value>Default Token Provider</value>
<comment>Name of the default token provider</comment>
</data>
<data name="DuplicateEmail" xml:space="preserve">
<value>Email '{0}' is already taken.</value>
<comment>error for duplicate emails</comment>
<comment>Error for duplicate emails</comment>
</data>
<data name="DuplicateRoleName" xml:space="preserve">
<value>Role Name '{0}' is already taken.</value>
<comment>error for duplicate usernames</comment>
<value>Role name '{0}' is already taken.</value>
<comment>Error for duplicate user names</comment>
</data>
<data name="DuplicateUserName" xml:space="preserve">
<value>UserName '{0}' is already taken.</value>
<comment>error for duplicate usernames</comment>
<value>User name '{0}' is already taken.</value>
<comment>Error for duplicate user names</comment>
</data>
<data name="InvalidEmail" xml:space="preserve">
<value>Email '{0}' is invalid.</value>
<comment>invalid email</comment>
<comment>Invalid email</comment>
</data>
<data name="InvalidPasswordHasherCompatibilityMode" xml:space="preserve">
<value>The provided PasswordHasherCompatibilityMode is invalid.</value>
@ -175,7 +175,7 @@
</data>
<data name="InvalidRoleName" xml:space="preserve">
<value>Role name '{0}' is invalid.</value>
<comment>error for invalid role names</comment>
<comment>Error for invalid role names</comment>
</data>
<data name="InvalidToken" xml:space="preserve">
<value>Invalid token.</value>
@ -183,7 +183,7 @@
</data>
<data name="InvalidUserName" xml:space="preserve">
<value>User name '{0}' is invalid, can only contain letters or digits.</value>
<comment>usernames can only contain letters or digits</comment>
<comment>User names can only contain letters or digits</comment>
</data>
<data name="LoginAlreadyAssociated" xml:space="preserve">
<value>A user with this login already exists.</value>
@ -223,63 +223,63 @@
</data>
<data name="RoleNotFound" xml:space="preserve">
<value>Role {0} does not exist.</value>
<comment>error when a role does not exist</comment>
<comment>Error when a role does not exist</comment>
</data>
<data name="StoreNotIQueryableRoleStore" xml:space="preserve">
<value>Store does not implement IQueryableRoleStore&lt;TRole&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIQueryableUserStore" xml:space="preserve">
<value>Store does not implement IQueryableUserStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIRoleClaimStore" xml:space="preserve">
<value>Store does not implement IRoleClaimStore&lt;TRole&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserClaimStore" xml:space="preserve">
<value>Store does not implement IUserClaimStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserConfirmationStore" xml:space="preserve">
<value>Store does not implement IUserConfirmationStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserEmailStore" xml:space="preserve">
<value>Store does not implement IUserEmailStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserLockoutStore" xml:space="preserve">
<value>Store does not implement IUserLockoutStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserLoginStore" xml:space="preserve">
<value>Store does not implement IUserLoginStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserPasswordStore" xml:space="preserve">
<value>Store does not implement IUserPasswordStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserPhoneNumberStore" xml:space="preserve">
<value>Store does not implement IUserPhoneNumberStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserRoleStore" xml:space="preserve">
<value>Store does not implement IUserRoleStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserSecurityStampStore" xml:space="preserve">
<value>Store does not implement IUserSecurityStampStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="StoreNotIUserTwoFactorStore" xml:space="preserve">
<value>Store does not implement IUserTwoFactorStore&lt;TUser&gt;.</value>
<comment>error when the store does not implement this interface</comment>
<comment>Error when the store does not implement this interface</comment>
</data>
<data name="UserAlreadyHasPassword" xml:space="preserve">
<value>User already has a password set.</value>
<comment>error when AddPasswordAsync called when a user already has a password</comment>
<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 '{0}'.</value>
@ -291,14 +291,34 @@
</data>
<data name="UserLockoutNotEnabled" xml:space="preserve">
<value>Lockout is not enabled for this user.</value>
<comment>error when lockout is not enabled</comment>
<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>
<comment>Error when a user does not exist</comment>
</data>
<data name="UserNotInRole" xml:space="preserve">
<value>User is not in role '{0}'.</value>
<comment>Error when a user is not in the role</comment>
</data>
<data name="LogIdentityResultFailure" xml:space="preserve">
<value>{0} : Failed : {1}</value>
<comment>Logging method execution failure</comment>
</data>
<data name="LogIdentityResultSuccess" xml:space="preserve">
<value>{0} : Success</value>
<comment>Logging method execution success</comment>
</data>
<data name="LoggingSigninResult" xml:space="preserve">
<value>{0} : Result : {1}</value>
<comment>Logging statement for SignInManager</comment>
</data>
<data name="LoggingResultMessage" xml:space="preserve">
<value>{0} for user: {1}</value>
<comment>Message prefix for Identity result</comment>
</data>
<data name="LoggingResultMessageForRole" xml:space="preserve">
<value>{0} for role: {1}</value>
<comment>Message prefix for Identity result for role operation</comment>
</data>
</root>

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Identity
{
@ -23,10 +24,11 @@ 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,
public RoleManager(IRoleStore<TRole> store,
IEnumerable<IRoleValidator<TRole>> roleValidators = null,
ILookupNormalizer keyNormalizer = null,
IdentityErrorDescriber errors = null)
IdentityErrorDescriber errors = null,
ILoggerFactory loggerFactory = null)
{
if (store == null)
{
@ -43,6 +45,9 @@ namespace Microsoft.AspNet.Identity
RoleValidators.Add(v);
}
}
loggerFactory = loggerFactory ?? new LoggerFactory();
Logger = loggerFactory.Create(nameof(RoleManager<TRole>));
}
/// <summary>
@ -60,6 +65,11 @@ namespace Microsoft.AspNet.Identity
/// </summary>
public IdentityErrorDescriber ErrorDescriber { get; set; }
/// <summary>
/// Used to log results
/// </summary>
public ILogger Logger { get; set; }
/// <summary>
/// Used to normalize user names, role names, emails for uniqueness
/// </summary>
@ -134,7 +144,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="role"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> CreateAsync(TRole role,
public virtual async Task<IdentityResult> CreateAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -149,7 +159,7 @@ namespace Microsoft.AspNet.Identity
return result;
}
await UpdateNormalizedRoleNameAsync(role, cancellationToken);
return await Store.CreateAsync(role, cancellationToken);
return await LogResultAsync(await Store.CreateAsync(role, cancellationToken), role);
}
/// <summary>
@ -172,7 +182,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="role"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> UpdateAsync(TRole role,
public virtual async Task<IdentityResult> UpdateAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -181,6 +191,12 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("role");
}
return await LogResultAsync(await UpdateRoleAsync(role, cancellationToken), role);
}
private async Task<IdentityResult> UpdateRoleAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
var result = await ValidateRoleInternal(role, cancellationToken);
if (!result.Succeeded)
{
@ -196,7 +212,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="role"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> DeleteAsync(TRole role,
public virtual async Task<IdentityResult> DeleteAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -204,7 +220,7 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("role");
}
return await Store.DeleteAsync(role, cancellationToken);
return await LogResultAsync(await Store.DeleteAsync(role, cancellationToken), role);
}
/// <summary>
@ -213,7 +229,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="roleName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<bool> RoleExistsAsync(string roleName,
public virtual async Task<bool> RoleExistsAsync(string roleName,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -242,7 +258,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="roleId"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<TRole> FindByIdAsync(string roleId,
public virtual async Task<TRole> FindByIdAsync(string roleId,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -255,7 +271,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="role"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<string> GetRoleNameAsync(TRole role,
public virtual async Task<string> GetRoleNameAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -269,13 +285,13 @@ namespace Microsoft.AspNet.Identity
/// <param name="name"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> SetRoleNameAsync(TRole role, string name,
public virtual async Task<IdentityResult> SetRoleNameAsync(TRole role, string name,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
await Store.SetRoleNameAsync(role, name, cancellationToken);
await UpdateNormalizedRoleNameAsync(role, cancellationToken);
return IdentityResult.Success;
return await LogResultAsync(IdentityResult.Success, role);
}
/// <summary>
@ -284,7 +300,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="role"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<string> GetRoleIdAsync(TRole role,
public virtual async Task<string> GetRoleIdAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -297,7 +313,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="roleName"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<TRole> FindByNameAsync(string roleName,
public virtual async Task<TRole> FindByNameAsync(string roleName,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -327,7 +343,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="claim"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> AddClaimAsync(TRole role, Claim claim,
public virtual async Task<IdentityResult> AddClaimAsync(TRole role, Claim claim,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -341,7 +357,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("role");
}
await claimStore.AddClaimAsync(role, claim, cancellationToken);
return await UpdateAsync(role, cancellationToken);
return await LogResultAsync(await UpdateRoleAsync(role, cancellationToken), role);
}
/// <summary>
@ -351,7 +367,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="claim"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> RemoveClaimAsync(TRole role, Claim claim,
public virtual async Task<IdentityResult> RemoveClaimAsync(TRole role, Claim claim,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -361,7 +377,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("role");
}
await claimStore.RemoveClaimAsync(role, claim, cancellationToken);
return await UpdateAsync(role, cancellationToken);
return await LogResultAsync(await UpdateRoleAsync(role, cancellationToken), role);
}
/// <summary>
@ -370,7 +386,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="role"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<IList<Claim>> GetClaimsAsync(TRole role,
public virtual async Task<IList<Claim>> GetClaimsAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -382,6 +398,21 @@ namespace Microsoft.AspNet.Identity
return await claimStore.GetClaimsAsync(role, cancellationToken);
}
/// <summary>
/// Logs the current Identity Result and returns result object
/// </summary>
/// <param name="result"></param>
/// <param name="user"></param>
/// <param name="methodName"></param>
/// <returns></returns>
protected async Task<IdentityResult> LogResultAsync(IdentityResult result,
TRole role, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "")
{
result.Log(Logger, Resources.FormatLoggingResultMessageForRole(methodName, await GetRoleIdAsync(role)));
return result;
}
private void ThrowIfDisposed()
{
if (_disposed)

View File

@ -11,6 +11,7 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Security;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Identity
@ -21,10 +22,11 @@ namespace Microsoft.AspNet.Identity
/// <typeparam name="TUser"></typeparam>
public class SignInManager<TUser> where TUser : class
{
public SignInManager(UserManager<TUser> userManager,
IHttpContextAccessor contextAccessor,
IClaimsIdentityFactory<TUser> claimsFactory,
IOptions<IdentityOptions> optionsAccessor = null)
public SignInManager(UserManager<TUser> userManager,
IHttpContextAccessor contextAccessor,
IClaimsIdentityFactory<TUser> claimsFactory,
IOptions<IdentityOptions> optionsAccessor = null,
ILoggerFactory loggerFactory = null)
{
if (userManager == null)
{
@ -38,16 +40,21 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException(nameof(claimsFactory));
}
UserManager = userManager;
Context = contextAccessor.Value;
ClaimsFactory = claimsFactory;
Options = optionsAccessor?.Options ?? new IdentityOptions();
loggerFactory = loggerFactory ?? new LoggerFactory();
Logger = loggerFactory.Create(nameof(SignInManager<TUser>));
}
public UserManager<TUser> UserManager { get; private set; }
public HttpContext Context { get; private set; }
public IClaimsIdentityFactory<TUser> ClaimsFactory { get; private set; }
public IdentityOptions Options { get; private set; }
public ILogger Logger { get; set; }
// Should this be a func?
public virtual async Task<ClaimsIdentity> CreateUserIdentityAsync(TUser user,
@ -61,13 +68,13 @@ namespace Microsoft.AspNet.Identity
{
if (Options.SignIn.RequireConfirmedEmail && !(await UserManager.IsEmailConfirmedAsync(user, cancellationToken)))
{
return false;
return await LogResultAsync(false, user);
}
if (Options.SignIn.RequireConfirmedPhoneNumber && !(await UserManager.IsPhoneNumberConfirmedAsync(user, cancellationToken)))
{
return false;
return await LogResultAsync(false, user);
}
return true;
return await LogResultAsync(true, user);
}
public virtual async Task SignInAsync(TUser user, bool isPersistent, string authenticationMethod = null,
@ -139,7 +146,7 @@ namespace Microsoft.AspNet.Identity
return null;
}
public virtual async Task<SignInResult> 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)
@ -149,16 +156,16 @@ namespace Microsoft.AspNet.Identity
var error = await PreSignInCheck(user, cancellationToken);
if (error != null)
{
return error;
return await LogResultAsync(error, user);
}
if (await IsLockedOut(user, cancellationToken))
{
return SignInResult.LockedOut;
return await LogResultAsync(SignInResult.LockedOut, user);
}
if (await UserManager.CheckPasswordAsync(user, password, cancellationToken))
{
await ResetLockout(user, cancellationToken);
return await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken);
return await LogResultAsync(await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken), user);
}
if (UserManager.SupportsUserLockout && shouldLockout)
{
@ -166,10 +173,11 @@ namespace Microsoft.AspNet.Identity
await UserManager.AccessFailedAsync(user, cancellationToken);
if (await UserManager.IsLockedOutAsync(user, cancellationToken))
{
return SignInResult.LockedOut;
return await LogResultAsync(SignInResult.LockedOut, user);
}
}
return SignInResult.Failed;
return await LogResultAsync(SignInResult.Failed, user);
}
public virtual async Task<SignInResult> PasswordSignInAsync(string userName, string password,
@ -214,7 +222,7 @@ namespace Microsoft.AspNet.Identity
}
var token = await UserManager.GenerateTwoFactorTokenAsync(user, provider, cancellationToken);
await UserManager.NotifyTwoFactorTokenAsync(user, provider, token, cancellationToken);
return true;
return await LogResultAsync(true, user);
}
public async Task<bool> IsTwoFactorClientRememberedAsync(TUser user,
@ -257,7 +265,7 @@ namespace Microsoft.AspNet.Identity
var error = await PreSignInCheck(user, cancellationToken);
if (error != null)
{
return error;
return await LogResultAsync(error, user);
}
if (await UserManager.VerifyTwoFactorTokenAsync(user, provider, code, cancellationToken))
{
@ -275,11 +283,11 @@ namespace Microsoft.AspNet.Identity
}
await UserManager.ResetAccessFailedCountAsync(user, cancellationToken);
await SignInAsync(user, isPersistent);
return SignInResult.Success;
return await LogResultAsync(SignInResult.Success, user);
}
// If the token is incorrect, record the failure which also may cause the user to be locked out
await UserManager.AccessFailedAsync(user, cancellationToken);
return SignInResult.Failed;
return await LogResultAsync(SignInResult.Failed, user);
}
/// <summary>
@ -310,9 +318,9 @@ namespace Microsoft.AspNet.Identity
var error = await PreSignInCheck(user, cancellationToken);
if (error != null)
{
return error;
return await LogResultAsync(error, user);
}
return await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken, loginProvider);
return await LogResultAsync(await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken, loginProvider), user);
}
private const string LoginProviderKey = "LoginProvider";
@ -323,7 +331,7 @@ namespace Microsoft.AspNet.Identity
return Context.GetAuthenticationTypes().Where(d => !string.IsNullOrEmpty(d.Caption));
}
public virtual async Task<ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null,
public virtual async Task<ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null,
CancellationToken cancellationToken = default(CancellationToken))
{
var auth = await Context.AuthenticateAsync(IdentityOptions.ExternalCookieAuthenticationType);
@ -368,7 +376,7 @@ namespace Microsoft.AspNet.Identity
private async Task<SignInResult> SignInOrTwoFactorAsync(TUser user, bool isPersistent,
CancellationToken cancellationToken, string loginProvider = null)
{
if (UserManager.SupportsUserTwoFactor &&
if (UserManager.SupportsUserTwoFactor &&
await UserManager.GetTwoFactorEnabledAsync(user, cancellationToken) &&
(await UserManager.GetValidTwoFactorProvidersAsync(user, cancellationToken)).Count > 0)
{
@ -403,6 +411,35 @@ namespace Microsoft.AspNet.Identity
return null;
}
/// <summary>
/// Log boolean result for user and return result
/// </summary>
/// <param name="result"></param>
/// <param name="user"></param>
/// <param name="methodName"></param>
/// <returns></returns>
protected async virtual Task<bool> LogResultAsync(bool result, TUser user, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "")
{
Logger.WriteInformation(Resources.FormatLoggingSigninResult(Resources.FormatLoggingResultMessage(methodName,
await UserManager.GetUserIdAsync(user)), result));
return result;
}
/// <summary>
/// Log SignInStatus for user and return SignInStatus
/// </summary>
/// <param name="status"></param>
/// <param name="user"></param>
/// <param name="methodName"></param>
/// <returns></returns>
protected async virtual Task<SignInResult> LogResultAsync(SignInResult status, TUser user, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "")
{
status.Log(Logger, Resources.FormatLoggingResultMessage(methodName, await UserManager.GetUserIdAsync(user)));
return status;
}
internal static ClaimsIdentity StoreTwoFactorInfo(string userId, string loginProvider)
{
var identity = new ClaimsIdentity(IdentityOptions.TwoFactorUserIdCookieAuthenticationType);

View File

@ -1,6 +1,8 @@
// 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.Logging;
namespace Microsoft.AspNet.Identity
{
/// <summary>
@ -78,5 +80,34 @@ namespace Microsoft.AspNet.Identity
{
get { return _twoFactorRequired; }
}
/// <summary>
/// Log result based on properties
/// </summary>
/// <param name="logger"></param>
/// <param name="message"></param>
public virtual void Log(ILogger logger, string message)
{
if (IsLockedOut)
{
logger.WriteInformation(Resources.FormatLoggingSigninResult(message, "Lockedout"));
}
else if (IsNotAllowed)
{
logger.WriteInformation(Resources.FormatLoggingSigninResult(message, "NotAllowed"));
}
else if (RequiresTwoFactor)
{
logger.WriteInformation(Resources.FormatLoggingSigninResult(message, "RequiresTwoFactor"));
}
else if (Succeeded)
{
logger.WriteInformation(Resources.FormatLoggingSigninResult(message, "Succeeded"));
}
else
{
logger.WriteInformation(Resources.FormatLoggingSigninResult(message, "Failed"));
}
}
}
}

View File

@ -9,6 +9,7 @@ using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Identity
@ -41,15 +42,17 @@ namespace Microsoft.AspNet.Identity
/// <param name="errors"></param>
/// <param name="tokenProviders"></param>
/// <param name="msgProviders"></param>
public UserManager(IUserStore<TUser> store,
/// <param name="loggerFactory"></param>
public UserManager(IUserStore<TUser> store,
IOptions<IdentityOptions> optionsAccessor = null,
IPasswordHasher<TUser> passwordHasher = null,
IPasswordHasher<TUser> passwordHasher = null,
IEnumerable<IUserValidator<TUser>> userValidators = null,
IEnumerable<IPasswordValidator<TUser>> passwordValidators = null,
IEnumerable<IPasswordValidator<TUser>> passwordValidators = null,
ILookupNormalizer keyNormalizer = null,
IdentityErrorDescriber errors = null,
IEnumerable<IUserTokenProvider<TUser>> tokenProviders = null,
IEnumerable<IIdentityMessageProvider> msgProviders = null)
IEnumerable<IUserTokenProvider<TUser>> tokenProviders = null,
IEnumerable<IIdentityMessageProvider> msgProviders = null,
ILoggerFactory loggerFactory = null)
{
if (store == null)
{
@ -60,6 +63,7 @@ namespace Microsoft.AspNet.Identity
PasswordHasher = passwordHasher ?? new PasswordHasher<TUser>();
KeyNormalizer = keyNormalizer ?? new UpperInvariantLookupNormalizer();
ErrorDescriber = errors ?? new IdentityErrorDescriber();
if (userValidators != null)
{
foreach (var v in userValidators)
@ -74,6 +78,10 @@ namespace Microsoft.AspNet.Identity
PasswordValidators.Add(v);
}
}
loggerFactory = loggerFactory ?? new LoggerFactory();
Logger = loggerFactory.Create(nameof(UserManager<TUser>));
if (tokenProviders != null)
{
foreach (var tokenProvider in tokenProviders)
@ -138,6 +146,11 @@ namespace Microsoft.AspNet.Identity
/// </summary>
public IdentityErrorDescriber ErrorDescriber { get; set; }
/// <summary>
/// Used to log IdentityResult
/// </summary>
public ILogger Logger { get; set; }
public IdentityOptions Options
{
get
@ -329,12 +342,31 @@ namespace Microsoft.AspNet.Identity
return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
}
public virtual Task<string> GenerateConcurrencyStampAsync(TUser user,
public virtual Task<string> GenerateConcurrencyStampAsync(TUser user,
CancellationToken token = default(CancellationToken))
{
return Task.FromResult(Guid.NewGuid().ToString());
}
/// <summary>
/// Validate user and update. Called by other UserManager methods
/// </summary>
/// <param name="user"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task<IdentityResult> UpdateUserAsync(TUser user,
CancellationToken cancellationToken = default(CancellationToken))
{
var result = await ValidateUserInternal(user, cancellationToken);
if (!result.Succeeded)
{
return result;
}
await UpdateNormalizedUserNameAsync(user, cancellationToken);
await UpdateNormalizedEmailAsync(user, cancellationToken);
return await Store.UpdateAsync(user, cancellationToken);
}
/// <summary>
/// Create a user with no password
/// </summary>
@ -357,7 +389,7 @@ namespace Microsoft.AspNet.Identity
}
await UpdateNormalizedUserNameAsync(user, cancellationToken);
await UpdateNormalizedEmailAsync(user, cancellationToken);
return await Store.CreateAsync(user, cancellationToken);
return await LogResultAsync(await Store.CreateAsync(user, cancellationToken), user);
}
/// <summary>
@ -374,14 +406,7 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
var result = await ValidateUserInternal(user, cancellationToken);
if (!result.Succeeded)
{
return result;
}
await UpdateNormalizedUserNameAsync(user, cancellationToken);
await UpdateNormalizedEmailAsync(user, cancellationToken);
return await Store.UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -398,7 +423,7 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
return await Store.DeleteAsync(user, cancellationToken);
return await LogResultAsync(await Store.DeleteAsync(user, cancellationToken), user);
}
/// <summary>
@ -527,7 +552,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("user");
}
await UpdateUserName(user, userName, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
private async Task UpdateUserName(TUser user, string userName, CancellationToken cancellationToken)
@ -566,11 +591,13 @@ namespace Microsoft.AspNet.Identity
return false;
}
var result = await VerifyPasswordAsync(passwordStore, user, password, cancellationToken);
if (result == PasswordVerificationResult.SuccessRehashNeeded) {
if (result == PasswordVerificationResult.SuccessRehashNeeded)
{
await UpdatePasswordHash(passwordStore, user, password, cancellationToken, validatePassword: false);
await UpdateAsync(user, cancellationToken);
await UpdateUserAsync(user, cancellationToken);
}
return result != PasswordVerificationResult.Failed;
return await LogResultAsync(result != PasswordVerificationResult.Failed, user);
}
/// <summary>
@ -588,7 +615,7 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
return await passwordStore.HasPasswordAsync(user, cancellationToken);
return await LogResultAsync(await passwordStore.HasPasswordAsync(user, cancellationToken), user);
}
/// <summary>
@ -610,14 +637,14 @@ namespace Microsoft.AspNet.Identity
var hash = await passwordStore.GetPasswordHashAsync(user, cancellationToken);
if (hash != null)
{
return IdentityResult.Failed(ErrorDescriber.UserAlreadyHasPassword());
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserAlreadyHasPassword()), user);
}
var result = await UpdatePasswordHash(passwordStore, user, password, cancellationToken);
if (!result.Succeeded)
{
return result;
return await LogResultAsync(result, user);
}
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -642,11 +669,11 @@ namespace Microsoft.AspNet.Identity
var result = await UpdatePasswordHash(passwordStore, user, newPassword, cancellationToken);
if (!result.Succeeded)
{
return result;
return await LogResultAsync(result, user);
}
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
return IdentityResult.Failed(ErrorDescriber.PasswordMismatch());
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.PasswordMismatch()), user);
}
/// <summary>
@ -665,13 +692,13 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("user");
}
await UpdatePasswordHash(passwordStore, user, null, cancellationToken, validatePassword: false);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
internal async Task<IdentityResult> UpdatePasswordHash(IUserPasswordStore<TUser> passwordStore,
TUser user, string newPassword, CancellationToken cancellationToken, bool validatePassword = true)
{
if (validatePassword)
if (validatePassword)
{
var validate = await ValidatePasswordInternal(user, newPassword, cancellationToken);
if (!validate.Succeeded)
@ -746,7 +773,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("user");
}
await UpdateSecurityStampInternal(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -759,7 +786,10 @@ namespace Microsoft.AspNet.Identity
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
return await GenerateUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword", cancellationToken);
var token = await GenerateUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword", cancellationToken);
await LogResultAsync(IdentityResult.Success, user);
return token;
}
/// <summary>
@ -781,15 +811,15 @@ 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(ErrorDescriber.InvalidToken());
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
}
var passwordStore = GetPasswordStore();
var result = await UpdatePasswordHash(passwordStore, user, newPassword, cancellationToken);
if (!result.Succeeded)
{
return result;
return await LogResultAsync(result, user);
}
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
// Update the security stamp if the store supports it
@ -866,7 +896,7 @@ namespace Microsoft.AspNet.Identity
}
await loginStore.RemoveLoginAsync(user, loginProvider, providerKey, cancellationToken);
await UpdateSecurityStampInternal(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -892,10 +922,10 @@ namespace Microsoft.AspNet.Identity
var existingUser = await FindByLoginAsync(login.LoginProvider, login.ProviderKey, cancellationToken);
if (existingUser != null)
{
return IdentityResult.Failed(ErrorDescriber.LoginAlreadyAssociated());
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.LoginAlreadyAssociated()), user);
}
await loginStore.AddLoginAsync(user, login, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -971,7 +1001,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("user");
}
await claimStore.AddClaimsAsync(user, claims, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1000,7 +1030,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("user");
}
await claimStore.ReplaceClaimAsync(user, claim, newClaim, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1047,7 +1077,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("claims");
}
await claimStore.RemoveClaimsAsync(user, claims, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1097,10 +1127,10 @@ namespace Microsoft.AspNet.Identity
var userRoles = await userRoleStore.GetRolesAsync(user, cancellationToken);
if (userRoles.Contains(role))
{
return IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role));
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role)), user);
}
await userRoleStore.AddToRoleAsync(user, role, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1128,11 +1158,11 @@ namespace Microsoft.AspNet.Identity
{
if (userRoles.Contains(role))
{
return IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role));
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role)), user);
}
await userRoleStore.AddToRoleAsync(user, role, cancellationToken);
}
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1153,10 +1183,10 @@ namespace Microsoft.AspNet.Identity
}
if (!await userRoleStore.IsInRoleAsync(user, role, cancellationToken))
{
return IdentityResult.Failed(ErrorDescriber.UserNotInRole(role));
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserNotInRole(role)), user);
}
await userRoleStore.RemoveFromRoleAsync(user, role, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1183,11 +1213,11 @@ namespace Microsoft.AspNet.Identity
{
if (!await userRoleStore.IsInRoleAsync(user, role, cancellationToken))
{
return IdentityResult.Failed(ErrorDescriber.UserNotInRole(role));
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserNotInRole(role)), user);
}
await userRoleStore.RemoveFromRoleAsync(user, role, cancellationToken);
}
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1276,7 +1306,7 @@ namespace Microsoft.AspNet.Identity
await store.SetEmailAsync(user, email, cancellationToken);
await store.SetEmailConfirmedAsync(user, false, cancellationToken);
await UpdateSecurityStampInternal(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1321,11 +1351,14 @@ namespace Microsoft.AspNet.Identity
/// <param name="user"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual Task<string> GenerateEmailConfirmationTokenAsync(TUser user,
public async virtual Task<string> GenerateEmailConfirmationTokenAsync(TUser user,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
return GenerateUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "Confirmation", cancellationToken);
var token = await GenerateUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "Confirmation", cancellationToken);
await LogResultAsync(IdentityResult.Success, user);
return token;
}
/// <summary>
@ -1346,10 +1379,10 @@ namespace Microsoft.AspNet.Identity
}
if (!await VerifyUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "Confirmation", token, cancellationToken))
{
return IdentityResult.Failed(ErrorDescriber.InvalidToken());
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
}
await store.SetEmailConfirmedAsync(user, true, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1385,7 +1418,10 @@ namespace Microsoft.AspNet.Identity
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
return await GenerateUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail), cancellationToken);
var token = await GenerateUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail), cancellationToken);
await LogResultAsync(IdentityResult.Success, user);
return token;
}
/// <summary>
@ -1407,13 +1443,13 @@ 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(ErrorDescriber.InvalidToken());
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
}
var store = GetEmailStore();
await store.SetEmailAsync(user, newEmail, cancellationToken);
await store.SetEmailConfirmedAsync(user, true, cancellationToken);
await UpdateSecurityStampInternal(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
// IUserPhoneNumberStore methods
@ -1464,7 +1500,7 @@ namespace Microsoft.AspNet.Identity
await store.SetPhoneNumberAsync(user, phoneNumber, cancellationToken);
await store.SetPhoneNumberConfirmedAsync(user, false, cancellationToken);
await UpdateSecurityStampInternal(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1486,12 +1522,12 @@ namespace Microsoft.AspNet.Identity
}
if (!await VerifyChangePhoneNumberTokenAsync(user, token, phoneNumber, cancellationToken))
{
return IdentityResult.Failed(ErrorDescriber.InvalidToken());
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
}
await store.SetPhoneNumberAsync(user, phoneNumber, cancellationToken);
await store.SetPhoneNumberConfirmedAsync(user, true, cancellationToken);
await UpdateSecurityStampInternal(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1530,9 +1566,12 @@ namespace Microsoft.AspNet.Identity
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
return Rfc6238AuthenticationService.GenerateCode(
var token = Rfc6238AuthenticationService.GenerateCode(
await CreateSecurityTokenAsync(user, cancellationToken), phoneNumber)
.ToString(CultureInfo.InvariantCulture);
await LogResultAsync(IdentityResult.Success, user);
return token;
}
/// <summary>
@ -1550,8 +1589,13 @@ namespace Microsoft.AspNet.Identity
int code;
if (securityToken != null && Int32.TryParse(token, out code))
{
return Rfc6238AuthenticationService.ValidateCode(securityToken, code, phoneNumber);
if (Rfc6238AuthenticationService.ValidateCode(securityToken, code, phoneNumber))
{
await LogResultAsync(IdentityResult.Success, user);
return true;
}
}
await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
return false;
}
@ -1580,7 +1624,18 @@ namespace Microsoft.AspNet.Identity
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.NoTokenProvider, tokenProvider));
}
// Make sure the token is valid
return await _tokenProviders[tokenProvider].ValidateAsync(purpose, token, this, user, cancellationToken);
var result = await _tokenProviders[tokenProvider].ValidateAsync(purpose, token, this, user, cancellationToken);
if (result)
{
await LogResultAsync(IdentityResult.Success, user);
}
else
{
await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
}
return result;
}
/// <summary>
@ -1606,7 +1661,11 @@ namespace Microsoft.AspNet.Identity
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.NoTokenProvider, tokenProvider));
}
return await _tokenProviders[tokenProvider].GenerateAsync(purpose, this, user, cancellationToken);
var token = await _tokenProviders[tokenProvider].GenerateAsync(purpose, this, user, cancellationToken);
await LogResultAsync(IdentityResult.Success, user);
return token;
}
/// <summary>
@ -1684,7 +1743,18 @@ namespace Microsoft.AspNet.Identity
Resources.NoTokenProvider, tokenProvider));
}
// Make sure the token is valid
return await _tokenProviders[tokenProvider].ValidateAsync("TwoFactor", token, this, user, cancellationToken);
var result = await _tokenProviders[tokenProvider].ValidateAsync("TwoFactor", token, this, user, cancellationToken);
if (result)
{
await LogResultAsync(IdentityResult.Success, user);
}
else
{
await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
}
return result;
}
/// <summary>
@ -1707,7 +1777,10 @@ namespace Microsoft.AspNet.Identity
throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture,
Resources.NoTokenProvider, tokenProvider));
}
return await _tokenProviders[tokenProvider].GenerateAsync("TwoFactor", this, user, cancellationToken);
var token = await _tokenProviders[tokenProvider].GenerateAsync("TwoFactor", this, user, cancellationToken);
await LogResultAsync(IdentityResult.Success, user);
return token;
}
/// <summary>
@ -1736,7 +1809,7 @@ namespace Microsoft.AspNet.Identity
Resources.NoTokenProvider, tokenProvider));
}
await _tokenProviders[tokenProvider].NotifyAsync(token, this, user, cancellationToken);
return IdentityResult.Success;
return await LogResultAsync(IdentityResult.Success, user);
}
// IUserFactorStore methods
@ -1786,7 +1859,7 @@ namespace Microsoft.AspNet.Identity
}
await store.SetTwoFactorEnabledAsync(user, enabled, cancellationToken);
await UpdateSecurityStampInternal(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
// Messaging methods
@ -1798,7 +1871,7 @@ namespace Microsoft.AspNet.Identity
/// <param name="message"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> SendMessageAsync(string messageProvider, IdentityMessage message,
public virtual async Task<IdentityResult> SendMessageAsync(string messageProvider, IdentityMessage message,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@ -1866,7 +1939,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("user");
}
await store.SetLockoutEnabledAsync(user, enabled, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1923,10 +1996,10 @@ namespace Microsoft.AspNet.Identity
}
if (!await store.GetLockoutEnabledAsync(user, cancellationToken).ConfigureAwait((false)))
{
return IdentityResult.Failed(ErrorDescriber.UserLockoutNotEnabled());
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserLockoutNotEnabled()), user);
}
await store.SetLockoutEndDateAsync(user, lockoutEnd, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1950,12 +2023,12 @@ namespace Microsoft.AspNet.Identity
var count = await store.IncrementAccessFailedCountAsync(user, cancellationToken);
if (count < Options.Lockout.MaxFailedAccessAttempts)
{
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
await store.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.Add(Options.Lockout.DefaultLockoutTimeSpan),
cancellationToken);
await store.ResetAccessFailedCountAsync(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -1974,7 +2047,7 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("user");
}
await store.ResetAccessFailedCountAsync(user, cancellationToken);
return await UpdateAsync(user, cancellationToken);
return await LogResultAsync(await UpdateUserAsync(user, cancellationToken), user);
}
/// <summary>
@ -2026,6 +2099,44 @@ namespace Microsoft.AspNet.Identity
return store.GetUsersInRoleAsync(roleName, cancellationToken);
}
/// <summary>
/// Logs the current Identity Result and returns result object
/// </summary>
/// <param name="result"></param>
/// <param name="user"></param>
/// <param name="methodName"></param>
/// <returns></returns>
protected async Task<IdentityResult> LogResultAsync(IdentityResult result,
TUser user, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "")
{
result.Log(Logger, Resources.FormatLoggingResultMessage(methodName, await GetUserIdAsync(user)));
return result;
}
/// <summary>
/// Logs result of operation being true/false
/// </summary>
/// <param name="result"></param>
/// <param name="user"></param>
/// <param name="methodName"></param>
/// <returns>result</returns>
protected async Task<bool> LogResultAsync(bool result,
TUser user, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "")
{
var baseMessage = Resources.FormatLoggingResultMessage(methodName, await GetUserIdAsync(user));
if (result)
{
Logger.WriteInformation(string.Format("{0} : {1}", baseMessage, result.ToString()));
}
else
{
Logger.WriteWarning(string.Format("{0} : {1}", baseMessage, result.ToString()));
}
return result;
}
private void ThrowIfDisposed()
{
if (_disposed)

View File

@ -7,7 +7,8 @@
"Microsoft.AspNet.Security.DataProtection": "1.0.0-*",
"Microsoft.Framework.ConfigurationModel": "1.0.0-*",
"Microsoft.Framework.DependencyInjection" : "1.0.0-*",
"Microsoft.Framework.OptionsModel": "1.0.0-*"
"Microsoft.Framework.OptionsModel": "1.0.0-*",
"Microsoft.Framework.Logging": "1.0.0-*"
},
"frameworks": {
"aspnet50": {},

View File

@ -1,12 +1,13 @@
// 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 System;
using Microsoft.AspNet.Identity.Test;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Identity.EntityFramework.InMemory.Test
{
public class InMemoryEFUserStoreTest : UserManagerTestBase<IdentityUser, IdentityRole>
public class InMemoryEFUserStoreTest : UserManagerTestBase<IdentityUser, IdentityRole>,IDisposable
{
protected override object CreateTestContext()
{
@ -23,5 +24,10 @@ namespace Microsoft.AspNet.Identity.EntityFramework.InMemory.Test
var store = new RoleStore<IdentityRole, InMemoryContext>((InMemoryContext)context);
services.AddInstance<IRoleStore<IdentityRole>>(store);
}
public void Dispose()
{
loggerFactory.Dispose();
}
}
}

View File

@ -7,10 +7,7 @@ using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Identity.Test;
using Microsoft.Data.Entity;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Microsoft.Framework.OptionsModel;
using Microsoft.Framework.Runtime.Infrastructure;
using Xunit;
@ -37,6 +34,7 @@ namespace Microsoft.AspNet.Identity.EntityFramework.Test
public void DropDatabaseDone()
{
DropDb();
loggerFactory.Dispose();
}
public void DropDb()

View File

@ -1,12 +1,13 @@
// 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 System;
using Microsoft.AspNet.Identity.Test;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Identity.InMemory.Test
{
public class InMemoryStoreTest : UserManagerTestBase<InMemoryUser, IdentityRole>
public class InMemoryStoreTest : UserManagerTestBase<InMemoryUser, IdentityRole>, IDisposable
{
protected override object CreateTestContext()
{
@ -22,5 +23,10 @@ namespace Microsoft.AspNet.Identity.InMemory.Test
{
services.AddSingleton<IRoleStore<IdentityRole>, InMemoryRoleStore<IdentityRole>>();
}
public void Dispose()
{
loggerFactory.Dispose();
}
}
}

View File

@ -10,6 +10,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Identity.Test
{
@ -236,13 +237,13 @@ namespace Microsoft.AspNet.Identity.Test
private class MyUserManager : UserManager<TestUser>
{
public MyUserManager(IUserStore<TestUser> store) : base(store) { }
public MyUserManager(IUserStore<TestUser> store) : base(store) { }
}
private class MyRoleManager : RoleManager<TestRole>
{
public MyRoleManager(IRoleStore<TestRole> store,
IEnumerable<IRoleValidator<TestRole>> roleValidators) : base(store, roleValidators)
IEnumerable<IRoleValidator<TestRole>> roleValidators) : base(store)
{
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Text;
using Xunit;
namespace Microsoft.AspNet.Identity.Test
@ -23,5 +24,29 @@ namespace Microsoft.AspNet.Identity.Test
Assert.False(result.Succeeded);
Assert.Equal(0, result.Errors.Count());
}
[Fact]
public void VerifySuccessResultLog()
{
var result = IdentityResult.Success;
var logMessage = new StringBuilder();
var logger = MockHelpers.MockILogger(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Success", logMessage.ToString());
}
[Fact]
public void VerifyFailureResultLog()
{
var result = IdentityResult.Failed(new IdentityError() { Code = "Foo" }, new IdentityError() { Code = "Bar" });
var logMessage = new StringBuilder();
var logger = MockHelpers.MockILogger(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Failed : Foo,Bar", logMessage.ToString());
}
}
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
@ -14,4 +14,9 @@
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
<ProjectExtensions>
<VisualStudio>
<UserProperties project_1json__JSONSchema="http://www.asp.net/media/4878834/project.json" />
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@ -124,7 +124,7 @@ namespace Microsoft.AspNet.Identity.Test
public async Task RoleManagerPublicNullChecks()
{
Assert.Throws<ArgumentNullException>("store",
() => new RoleManager<TestRole>(null, null));
() => new RoleManager<TestRole>(null, null, null));
var manager = CreateRoleManager(new NotImplementedStore());
await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.CreateAsync(null));
await Assert.ThrowsAsync<ArgumentNullException>("role", async () => await manager.UpdateAsync(null));
@ -150,7 +150,7 @@ namespace Microsoft.AspNet.Identity.Test
{
var v = new List<IRoleValidator<TestRole>>();
v.Add(new RoleValidator<TestRole>());
return new RoleManager<TestRole>(roleStore, v);
return new RoleManager<TestRole>(roleStore);
}
private class NotImplementedStore : IRoleStore<TestRole>

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Identity.Test
{
// Setup
var validator = new RoleValidator<TestRole>();
var manager = new RoleManager<TestRole>(new NoopRoleStore(), null);
var manager = new RoleManager<TestRole>(new NoopRoleStore());
// Act
// Assert
@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Identity.Test
{
// Setup
var validator = new RoleValidator<TestRole>();
var manager = new RoleManager<TestRole>(new NoopRoleStore(), null);
var manager = new RoleManager<TestRole>(new NoopRoleStore());
var user = new TestRole {Name = input};
// Act

View File

@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Identity.Test
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock<SignInManager<IdentityUser>>(userManager.Object,
contextAccessor.Object, claimsManager.Object, options.Object);
contextAccessor.Object, claimsManager.Object, options.Object, null);
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsIdentity>(), user.Id, CancellationToken.None)).ReturnsAsync(user).Verifiable();
signInManager.Setup(s => s.SignInAsync(user, isPersistent, null, CancellationToken.None)).Returns(Task.FromResult(0)).Verifiable();
var services = new ServiceCollection();
@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Identity.Test
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock<SignInManager<IdentityUser>>(userManager.Object,
contextAccessor.Object, claimsManager.Object, options.Object);
contextAccessor.Object, claimsManager.Object, options.Object, null);
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsIdentity>(), user.Id, CancellationToken.None)).ReturnsAsync(null).Verifiable();
var services = new ServiceCollection();
services.AddInstance(options.Object);
@ -116,7 +116,7 @@ namespace Microsoft.AspNet.Identity.Test
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock<SignInManager<IdentityUser>>(userManager.Object,
contextAccessor.Object, claimsManager.Object, options.Object);
contextAccessor.Object, claimsManager.Object, options.Object, null);
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsIdentity>(), user.Id, CancellationToken.None)).ReturnsAsync(null).Verifiable();
var services = new ServiceCollection();
services.AddInstance(options.Object);
@ -150,7 +150,7 @@ namespace Microsoft.AspNet.Identity.Test
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock<SignInManager<IdentityUser>>(userManager.Object,
contextAccessor.Object, claimsManager.Object, options.Object);
contextAccessor.Object, claimsManager.Object, options.Object, null);
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny<ClaimsIdentity>(), user.Id, CancellationToken.None)).Throws(new Exception("Shouldn't be called"));
signInManager.Setup(s => s.SignInAsync(user, false, null, CancellationToken.None)).Throws(new Exception("Shouldn't be called"));
var services = new ServiceCollection();

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
@ -68,7 +69,7 @@ namespace Microsoft.AspNet.Identity.Test
[Fact]
public void ConstructorNullChecks()
{
Assert.Throws<ArgumentNullException>("userManager", () => new SignInManager<IdentityUser>(null, null, null, null));
Assert.Throws<ArgumentNullException>("userManager", () => new SignInManager<IdentityUser>(null, null, null, null, null));
var userManager = MockHelpers.MockUserManager<IdentityUser>().Object;
Assert.Throws<ArgumentNullException>("contextAccessor", () => new SignInManager<IdentityUser>(userManager, null, null, null));
var contextAccessor = new Mock<IHttpContextAccessor>();
@ -117,6 +118,8 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
manager.Setup(m => m.IsLockedOutAsync(user, CancellationToken.None)).ReturnsAsync(true).Verifiable();
manager.Setup(m => m.FindByNameAsync(user.UserName, CancellationToken.None)).ReturnsAsync(user).Verifiable();
manager.Setup(m => m.GetUserIdAsync(user, CancellationToken.None)).ReturnsAsync(user.Id.ToString()).Verifiable();
var context = new Mock<HttpContext>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
@ -125,7 +128,10 @@ namespace Microsoft.AspNet.Identity.Test
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, loggerFactory.Object);
string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "Lockedout");
// Act
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
@ -133,9 +139,10 @@ namespace Microsoft.AspNet.Identity.Test
// Assert
Assert.False(result.Succeeded);
Assert.True(result.IsLockedOut);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
manager.VerifyAll();
}
[Theory]
[InlineData(true)]
[InlineData(false)]
@ -149,6 +156,8 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.FindByNameAsync(user.UserName, CancellationToken.None)).ReturnsAsync(user).Verifiable();
manager.Setup(m => m.CheckPasswordAsync(user, "password", CancellationToken.None)).ReturnsAsync(true).Verifiable();
manager.Setup(m => m.ResetAccessFailedCountAsync(user, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
manager.Setup(m => m.GetUserIdAsync(user, CancellationToken.None)).ReturnsAsync(user.Id.ToString()).Verifiable();
var context = new Mock<HttpContext>();
var response = new Mock<HttpResponse>();
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
@ -161,13 +170,17 @@ namespace Microsoft.AspNet.Identity.Test
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
claimsFactory.Setup(m => m.CreateAsync(user, CancellationToken.None)).ReturnsAsync(new ClaimsIdentity("Microsoft.AspNet.Identity")).Verifiable();
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, loggerFactory.Object);
string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "Succeeded");
// Act
var result = await helper.PasswordSignInAsync(user.UserName, "password", isPersistent, false);
// Assert
Assert.True(result.Succeeded);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
manager.VerifyAll();
context.VerifyAll();
response.VerifyAll();
@ -186,6 +199,8 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.FindByNameAsync(user.UserName, CancellationToken.None)).ReturnsAsync(user).Verifiable();
manager.Setup(m => m.CheckPasswordAsync(user, "password", CancellationToken.None)).ReturnsAsync(true).Verifiable();
manager.Setup(m => m.ResetAccessFailedCountAsync(user, CancellationToken.None)).ReturnsAsync(IdentityResult.Success).Verifiable();
manager.Setup(m => m.GetUserIdAsync(user, CancellationToken.None)).ReturnsAsync(user.Id.ToString()).Verifiable();
var context = new Mock<HttpContext>();
var response = new Mock<HttpResponse>();
response.Setup(r => r.SignIn(It.IsAny<AuthenticationProperties>(), It.IsAny<ClaimsIdentity>())).Verifiable();
@ -245,7 +260,10 @@ namespace Microsoft.AspNet.Identity.Test
var identityOptions = new IdentityOptions();
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, new ClaimsIdentityFactory<TestUser, TestRole>(manager.Object, roleManager.Object, options.Object), options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, new ClaimsIdentityFactory<TestUser, TestRole>(manager.Object, roleManager.Object, options.Object), options.Object, loggerFactory.Object);
string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "RequiresTwoFactor");
// Act
var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false);
@ -253,6 +271,7 @@ namespace Microsoft.AspNet.Identity.Test
// Assert
Assert.False(result.Succeeded);
Assert.True(result.RequiresTwoFactor);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
manager.VerifyAll();
context.VerifyAll();
response.VerifyAll();
@ -277,6 +296,8 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.IsLockedOutAsync(user, CancellationToken.None)).ReturnsAsync(false).Verifiable();
}
manager.Setup(m => m.FindByLoginAsync(loginProvider, providerKey, CancellationToken.None)).ReturnsAsync(user).Verifiable();
manager.Setup(m => m.GetUserIdAsync(user, CancellationToken.None)).ReturnsAsync(user.Id.ToString()).Verifiable();
var context = new Mock<HttpContext>();
var response = new Mock<HttpResponse>();
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
@ -292,13 +313,17 @@ namespace Microsoft.AspNet.Identity.Test
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
claimsFactory.Setup(m => m.CreateAsync(user, CancellationToken.None)).ReturnsAsync(new ClaimsIdentity("Microsoft.AspNet.Identity")).Verifiable();
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, loggerFactory.Object);
string expected = string.Format("{0} for user: {1} : Result : {2}", "ExternalLoginSignInAsync", user.Id.ToString(), "Succeeded");
// Act
var result = await helper.ExternalLoginSignInAsync(loginProvider, providerKey, isPersistent);
// Assert
Assert.True(result.Succeeded);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
manager.VerifyAll();
context.VerifyAll();
response.VerifyAll();
@ -323,7 +348,6 @@ namespace Microsoft.AspNet.Identity.Test
[InlineData(false, true, false, false)]
[InlineData(false, false, true, false)]
[InlineData(false, false, false, false)]
public async Task CanTwoFactorSignIn(bool isPersistent, bool supportsLockout, bool externalLogin, bool rememberClient)
{
// Setup
@ -377,13 +401,17 @@ namespace Microsoft.AspNet.Identity.Test
context.Setup(c => c.Response).Returns(response.Object).Verifiable();
context.Setup(c => c.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationType)).ReturnsAsync(authResult).Verifiable();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, loggerFactory.Object);
string expected = string.Format("{0} for user: {1} : Result : {2}", "TwoFactorSignInAsync", user.Id.ToString(), "Succeeded");
// Act
var result = await helper.TwoFactorSignInAsync(provider, code, isPersistent, rememberClient);
// Assert
Assert.True(result.Succeeded);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
manager.VerifyAll();
context.VerifyAll();
response.VerifyAll();
@ -496,7 +524,9 @@ namespace Microsoft.AspNet.Identity.Test
options.Setup(a => a.Options).Returns(identityOptions);
IdentityOptions.ApplicationCookieAuthenticationType = authenticationType;
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, loggerFactory.Object);
// Act
helper.SignOut();
@ -518,6 +548,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.Setup(m => m.IsLockedOutAsync(user, CancellationToken.None)).ReturnsAsync(false).Verifiable();
manager.Setup(m => m.FindByNameAsync(user.UserName, CancellationToken.None)).ReturnsAsync(user).Verifiable();
manager.Setup(m => m.CheckPasswordAsync(user, "bogus", CancellationToken.None)).ReturnsAsync(false).Verifiable();
manager.Setup(m => m.GetUserIdAsync(user, CancellationToken.None)).ReturnsAsync(user.Id.ToString()).Verifiable();
var context = new Mock<HttpContext>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
@ -526,12 +557,16 @@ namespace Microsoft.AspNet.Identity.Test
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, loggerFactory.Object);
string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id.ToString(), "Failed");
// Act
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
// Assert
Assert.False(result.Succeeded);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
manager.VerifyAll();
context.VerifyAll();
contextAccessor.VerifyAll();
@ -611,6 +646,7 @@ namespace Microsoft.AspNet.Identity.Test
{
manager.Setup(m => m.CheckPasswordAsync(user, "password", CancellationToken.None)).ReturnsAsync(true).Verifiable();
}
manager.Setup(m => m.GetUserIdAsync(user, CancellationToken.None)).ReturnsAsync(user.Id.ToString()).Verifiable();
var context = new Mock<HttpContext>();
var response = new Mock<HttpResponse>();
if (confirmed)
@ -627,7 +663,10 @@ namespace Microsoft.AspNet.Identity.Test
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, loggerFactory.Object);
string expected = string.Format("{0} for user: {1} : Result : {2}", "CanSignInAsync", user.Id.ToString(), confirmed.ToString());
// Act
var result = await helper.PasswordSignInAsync(user, "password", false, false);
@ -636,6 +675,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Equal(confirmed, result.Succeeded);
Assert.NotEqual(confirmed, result.IsNotAllowed);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
manager.VerifyAll();
context.VerifyAll();
response.VerifyAll();
@ -650,7 +690,8 @@ namespace Microsoft.AspNet.Identity.Test
// Setup
var user = new TestUser { UserName = "Foo" };
var manager = MockHelpers.MockUserManager<TestUser>();
manager.Setup(m => m.IsEmailConfirmedAsync(user, CancellationToken.None)).ReturnsAsync(confirmed).Verifiable();
manager.Setup(m => m.IsPhoneNumberConfirmedAsync(user, CancellationToken.None)).ReturnsAsync(confirmed).Verifiable();
manager.Setup(m => m.GetUserIdAsync(user, CancellationToken.None)).ReturnsAsync(user.Id.ToString()).Verifiable();
var context = new Mock<HttpContext>();
var response = new Mock<HttpResponse>();
if (confirmed)
@ -664,11 +705,14 @@ namespace Microsoft.AspNet.Identity.Test
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager<TestRole>();
var identityOptions = new IdentityOptions();
identityOptions.SignIn.RequireConfirmedEmail = true;
identityOptions.SignIn.RequireConfirmedPhoneNumber = true;
var options = new Mock<IOptions<IdentityOptions>>();
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock<ClaimsIdentityFactory<TestUser, TestRole>>(manager.Object, roleManager.Object, options.Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
var logStore = new StringBuilder();
var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, loggerFactory.Object);
string expected = string.Format("{0} for user: {1} : Result : {2}", "CanSignInAsync", user.Id.ToString(), confirmed.ToString());
// Act
var result = await helper.PasswordSignInAsync(user, "password", false, false);
@ -676,6 +720,7 @@ namespace Microsoft.AspNet.Identity.Test
// Assert
Assert.Equal(confirmed, result.Succeeded);
Assert.NotEqual(confirmed, result.IsNotAllowed);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
manager.VerifyAll();
context.VerifyAll();
response.VerifyAll();

View File

@ -0,0 +1,71 @@
// 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 System.Text;
using Xunit;
namespace Microsoft.AspNet.Identity.Test
{
public class SignInResultTest
{
[Fact]
public void VerifyLogSuccess()
{
var result = SignInResult.Success;
var logMessage = new StringBuilder();
var logger = MockHelpers.MockILogger(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Result : Succeeded", logMessage.ToString());
}
[Fact]
public void VerifyLogLockedOut()
{
var result = SignInResult.LockedOut;
var logMessage = new StringBuilder();
var logger = MockHelpers.MockILogger(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Result : Lockedout", logMessage.ToString());
}
[Fact]
public void VerifyLogNotAllowed()
{
var result = SignInResult.NotAllowed;
var logMessage = new StringBuilder();
var logger = MockHelpers.MockILogger(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Result : NotAllowed", logMessage.ToString());
}
[Fact]
public void VerifyLogRequiresTwoFactor()
{
var result = SignInResult.TwoFactorRequired;
var logMessage = new StringBuilder();
var logger = MockHelpers.MockILogger(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Result : RequiresTwoFactor", logMessage.ToString());
}
[Fact]
public void VerifyLogRequiresFailed()
{
var result = SignInResult.Failed;
var logMessage = new StringBuilder();
var logger = MockHelpers.MockILogger(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Result : Failed", logMessage.ToString());
}
}
}

View File

@ -175,7 +175,7 @@ namespace Microsoft.AspNet.Identity.Test
{
// Setup
var store = new Mock<IUserStore<TestUser>>();
var user = new TestUser {UserName="Foo"};
var user = new TestUser { UserName = "Foo" };
store.Setup(s => s.FindByNameAsync(user.UserName.ToUpperInvariant(), CancellationToken.None)).Returns(Task.FromResult(user)).Verifiable();
var userManager = MockHelpers.TestUserManager<TestUser>(store.Object);
@ -192,7 +192,7 @@ namespace Microsoft.AspNet.Identity.Test
{
// Setup
var store = new Mock<IUserStore<TestUser>>();
var user = new TestUser {UserName="Foo"};
var user = new TestUser { UserName = "Foo" };
store.Setup(s => s.FindByNameAsync(user.UserName, CancellationToken.None)).Returns(Task.FromResult(user)).Verifiable();
var userManager = MockHelpers.TestUserManager(store.Object);
userManager.KeyNormalizer = null;
@ -246,7 +246,7 @@ namespace Microsoft.AspNet.Identity.Test
// Setup
var store = new Mock<IUserRoleStore<TestUser>>();
var user = new TestUser { UserName = "Foo" };
var roles = new string[] {"A", "B", "C"};
var roles = new string[] { "A", "B", "C" };
store.Setup(s => s.AddToRoleAsync(user, "A", CancellationToken.None))
.Returns(Task.FromResult(0))
.Verifiable();
@ -642,7 +642,7 @@ namespace Microsoft.AspNet.Identity.Test
var store = new NotImplementedStore();
Assert.Throws<ArgumentNullException>("store",
() => new UserManager<TestUser>(null));
() => new UserManager<TestUser>(null, null));
var manager = new UserManager<TestUser>(store);
@ -682,7 +682,7 @@ namespace Microsoft.AspNet.Identity.Test
await Assert.ThrowsAsync<ArgumentNullException>("user",
async () => await manager.AddClaimAsync(null, new Claim("a", "b")));
await Assert.ThrowsAsync<ArgumentNullException>("user",
async () => await manager.AddLoginAsync(null, new UserLoginInfo("","","")));
async () => await manager.AddLoginAsync(null, new UserLoginInfo("", "", "")));
await Assert.ThrowsAsync<ArgumentNullException>("user",
async () => await manager.AddPasswordAsync(null, null));
await Assert.ThrowsAsync<ArgumentNullException>("user",

View File

@ -1,7 +1,9 @@
// 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 System.IO;
using System.Linq;
using Microsoft.Framework.Logging;
using Xunit;
namespace Microsoft.AspNet.Identity.Test
@ -35,5 +37,69 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Equal(error.Code, result.Errors.First().Code);
}
public static void VerifyUserManagerFailureLog(ILogger logger, string methodName, string userId, params IdentityError[] errors)
{
VerifyFailureLog(logger, "UserManager", methodName, userId, "user", errors);
}
public static void VerifyRoleManagerFailureLog(ILogger logger, string methodName, string roleId, params IdentityError[] errors)
{
VerifyFailureLog(logger, "RoleManager", methodName, roleId, "role", errors);
}
public static void VerifyUserManagerSuccessLog(ILogger logger, string methodName, string userId)
{
VerifySuccessLog(logger, "UserManager", methodName, userId, "user");
}
public static void VerifyRoleManagerSuccessLog(ILogger logger, string methodName, string roleId)
{
VerifySuccessLog(logger, "RoleManager", methodName, roleId, "role");
}
private static void VerifySuccessLog(ILogger logger, string className, string methodName, string id, string userOrRole = "user")
{
if (logger is TestFileLogger)
{
var fileLogger = logger as TestFileLogger;
string expected = string.Format("{0} for {1}: {2} : Success", methodName, userOrRole, id);
Assert.True(File.ReadAllText(fileLogger.FileName).Contains(expected));
}
else
{
Assert.True(true, "No logger registered");
}
}
public static void VerifyLogMessage(ILogger logger, string expectedLog)
{
if (logger is TestFileLogger)
{
var fileLogger = logger as TestFileLogger;
Assert.True(File.ReadAllText(fileLogger.FileName).Contains(expectedLog));
}
else
{
Assert.True(true, "No logger registered");
}
}
private static void VerifyFailureLog(ILogger logger, string className, string methodName, string userId, string userOrRole = "user", params IdentityError[] errors)
{
if (logger is TestFileLogger)
{
var fileLogger = logger as TestFileLogger;
errors = errors ?? new IdentityError[] { new IdentityError() };
string expected = string.Format("{0} for {1}: {2} : Failed : {3}", methodName, userOrRole, userId, string.Join(",", errors.Select(x => x.Code).ToList()));
Assert.True(File.ReadAllText(fileLogger.FileName).Contains(expected));
}
else
{
Assert.True(true, "No logger registered");
}
}
}
}

View File

@ -1,20 +1,24 @@
// 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 System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Framework.OptionsModel;
using Microsoft.Framework.Logging;
using Moq;
using System.Text;
namespace Microsoft.AspNet.Identity.Test
{
public static class MockHelpers
{
public static StringBuilder LogMessage = new StringBuilder();
public static Mock<UserManager<TUser>> MockUserManager<TUser>() where TUser : class
{
var store = new Mock<IUserStore<TUser>>();
var mgr = new Mock<UserManager<TUser>>(store.Object, null, null, null, null, null, null, null, null);
var mgr = new Mock<UserManager<TUser>>(store.Object, null, null, null, null, null, null, null, null, null);
mgr.Object.UserValidators.Add(new UserValidator<TUser>());
mgr.Object.PasswordValidators.Add(new PasswordValidator<TUser>());
return mgr;
@ -25,7 +29,37 @@ namespace Microsoft.AspNet.Identity.Test
store = store ?? new Mock<IRoleStore<TRole>>().Object;
var roles = new List<IRoleValidator<TRole>>();
roles.Add(new RoleValidator<TRole>());
return new Mock<RoleManager<TRole>>(store, roles, null, null);
return new Mock<RoleManager<TRole>>(store, roles, null, null,null);
}
public static Mock<ILogger> MockILogger(StringBuilder logStore = null)
{
logStore = logStore ?? LogMessage;
var logger = new Mock<ILogger>();
logger.Setup(x => x.Write(It.IsAny<LogLevel>(), It.IsAny<int>(), It.IsAny<object>(),
It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()))
.Callback((LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter) =>
{ logStore.Append(state.ToString()); });
logger.Setup(x => x.IsEnabled(LogLevel.Information)).Returns(true);
logger.Setup(x => x.IsEnabled(LogLevel.Warning)).Returns(true);
return logger;
}
public static Mock<ILoggerFactory> MockILoggerFactory(ILogger logger = null)
{
logger = logger ?? MockILogger().Object;
var loggerFactory = new Mock<ILoggerFactory>();
loggerFactory.Setup(x => x.Create(It.IsAny<string>())).Returns(logger);
return loggerFactory;
}
public static UserManager<TUser> UserManagerWithMockLogger<TUser>(ILoggerFactory loggerFactory = null) where TUser : class
{
var userstore = new Mock<IUserStore<TUser>>().Object;
var userManager = new UserManager<TUser>(userstore, loggerFactory: loggerFactory ?? MockILoggerFactory().Object);
return userManager;
}
public static UserManager<TUser> TestUserManager<TUser>(IUserStore<TUser> store = null) where TUser : class

View File

@ -0,0 +1,45 @@
// 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 System;
using System.IO;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Identity.Test
{
public class TestFileLogger : ILogger
{
public string FileName { get; set; }
public object FileLock { get; private set; } = new object();
public TestFileLogger(string name)
{
var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "IdentityTests");
Directory.CreateDirectory(directory);
FileName = Path.Combine(directory, (name + DateTime.Now.Ticks + "log.txt"));
if (!File.Exists(FileName))
{
File.Create(FileName).Close();
}
}
public IDisposable BeginScope(object state)
{
throw new NotImplementedException();
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
lock (FileLock)
{
File.AppendAllLines(FileName, new string[] { state.ToString() });
}
}
}
}

View File

@ -0,0 +1,48 @@
// 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 System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.IO;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Identity.Test
{
public class TestFileLoggerFactory : ILoggerFactory, IDisposable
{
private static Dictionary<string, ILogger> _loggers;
static TestFileLoggerFactory()
{
_loggers = new Dictionary<string, ILogger>();
}
public void AddProvider(ILoggerProvider provider)
{
}
public ILogger Create(string name)
{
if (!_loggers.ContainsKey(name))
{
_loggers.Add(name, new TestFileLogger(name));
}
return _loggers[name];
}
public void Dispose()
{
Parallel.ForEach(_loggers.Values, l =>
{
if(l is TestFileLogger)
{
var logger = l as TestFileLogger;
File.Delete(logger.FileName);
}
});
}
}
}

View File

@ -10,6 +10,7 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Testing;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using Microsoft.Framework.Logging;
using Xunit;
namespace Microsoft.AspNet.Identity.Test
@ -20,17 +21,25 @@ namespace Microsoft.AspNet.Identity.Test
where TRole : IdentityRole, new()
{ }
public abstract class UserManagerTestBase<TUser, TRole, TKey>
where TUser: IdentityUser<TKey>, new()
where TRole: IdentityRole<TKey>, new()
public abstract class UserManagerTestBase<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>, new()
where TRole : IdentityRole<TKey>, new()
where TKey : IEquatable<TKey>
{
protected TestFileLoggerFactory loggerFactory;
public UserManagerTestBase()
{
loggerFactory = new TestFileLoggerFactory();
}
protected virtual void SetupIdentityServices(IServiceCollection services, object context = null)
{
services.AddHosting();
services.AddIdentity<TUser, TRole>().AddDefaultTokenProviders();
AddUserStore(services, context);
AddRoleStore(services, context);
services.AddInstance<ILoggerFactory>(loggerFactory);
services.ConfigureIdentity(options =>
{
options.Password.RequireDigit = false;
@ -74,11 +83,13 @@ namespace Microsoft.AspNet.Identity.Test
protected abstract void AddUserStore(IServiceCollection services, object context = null);
protected abstract void AddRoleStore(IServiceCollection services, object context = null);
protected TUser CreateTestUser(string namePrefix = "") {
protected TUser CreateTestUser(string namePrefix = "")
{
return new TUser() { UserName = namePrefix + Guid.NewGuid().ToString() };
}
protected TRole CreateRole(string namePrefix = "") {
protected TRole CreateRole(string namePrefix = "")
{
return new TRole() { Name = namePrefix + Guid.NewGuid().ToString() };
}
@ -88,7 +99,11 @@ namespace Microsoft.AspNet.Identity.Test
var manager = CreateManager();
var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "CreateAsync", user.Id.ToString());
IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "DeleteAsync", user.Id.ToString());
Assert.Null(await manager.FindByIdAsync(user.Id.ToString()));
}
@ -103,6 +118,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Null(await manager.FindByNameAsync(newName));
user.UserName = newName;
IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "UpdateAsync", user.Id.ToString());
Assert.NotNull(await manager.FindByNameAsync(newName));
Assert.Null(await manager.FindByNameAsync(name));
}
@ -126,9 +142,14 @@ namespace Microsoft.AspNet.Identity.Test
var user = new TUser() { UserName = "UpdatePassword" };
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password"));
Assert.True(await manager.CheckPasswordAsync(user, "password"));
string expectedLog = string.Format("{0} for user: {1} : {2}", "CheckPasswordAsync", user.Id.ToString(), true.ToString());
IdentityResultAssert.VerifyLogMessage(manager.Logger, expectedLog);
user.PasswordHash = manager.PasswordHasher.HashPassword(user, "New");
IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user));
Assert.False(await manager.CheckPasswordAsync(user, "password"));
expectedLog = string.Format("{0} for user: {1} : {2}", "CheckPasswordAsync", user.Id.ToString(), false.ToString());
IdentityResultAssert.VerifyLogMessage(manager.Logger, expectedLog);
Assert.True(await manager.CheckPasswordAsync(user, "New"));
}
@ -160,6 +181,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.UserValidators.Clear();
manager.UserValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.UpdateAsync(user), AlwaysBadValidator.ErrorMessage);
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "UpdateAsync", user.Id.ToString(), AlwaysBadValidator.ErrorMessage);
}
[Fact]
@ -208,6 +230,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.PasswordValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.AddPasswordAsync(user, "password"),
AlwaysBadValidator.ErrorMessage);
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "AddPasswordAsync", user.Id.ToString(), AlwaysBadValidator.ErrorMessage);
}
[Fact]
@ -234,6 +257,17 @@ namespace Microsoft.AspNet.Identity.Test
manager.PasswordValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.ChangePasswordAsync(user, "password", "new"),
AlwaysBadValidator.ErrorMessage);
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "ChangePasswordAsync", user.Id.ToString(), AlwaysBadValidator.ErrorMessage);
}
[Fact]
public async Task PasswordValidatorCanBlockCreateUser()
{
var manager = CreateManager();
var user = CreateTestUser();
manager.PasswordValidators.Clear();
manager.PasswordValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.CreateAsync(user, "password"), AlwaysBadValidator.ErrorMessage);
}
[Fact]
@ -260,6 +294,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
user = await manager.FindByNameAsync(user.UserName);
IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, new UserLoginInfo(provider, providerKey, display)));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "AddLoginAsync", user.Id.ToString());
var logins = await manager.GetLoginsAsync(user);
Assert.NotNull(logins);
Assert.Equal(1, logins.Count());
@ -278,6 +313,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login));
Assert.False(await manager.HasPasswordAsync(user));
IdentityResultAssert.IsSuccess(await manager.AddPasswordAsync(user, "password"));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "AddPasswordAsync", user.Id.ToString());
Assert.True(await manager.HasPasswordAsync(user));
var logins = await manager.GetLoginsAsync(user);
Assert.NotNull(logins);
@ -295,6 +331,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.True(await manager.HasPasswordAsync(user));
IdentityResultAssert.IsFailure(await manager.AddPasswordAsync(user, "password"),
"User already has a password set.");
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "AddPasswordAsync", user.Id.ToString(), IdentityErrorDescriber.Default.UserAlreadyHasPassword());
}
[Fact]
@ -316,6 +353,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Equal(login.ProviderDisplayName, logins.Last().ProviderDisplayName);
var stamp = user.SecurityStamp;
IdentityResultAssert.IsSuccess(await manager.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "RemoveLoginAsync", user.Id.ToString());
Assert.Null(await manager.FindByLoginAsync(login.LoginProvider, login.ProviderKey));
logins = await manager.GetLoginsAsync(user);
Assert.NotNull(logins);
@ -332,6 +370,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password));
var stamp = user.SecurityStamp;
IdentityResultAssert.IsSuccess(await manager.RemovePasswordAsync(user));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "RemovePasswordAsync", user.Id.ToString());
var u = await manager.FindByNameAsync(user.UserName);
Assert.NotNull(u);
Assert.Null(u.PasswordHash);
@ -351,6 +390,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.ChangePasswordAsync(user, password, newPassword));
Assert.False(await manager.CheckPasswordAsync(user, password));
Assert.True(await manager.CheckPasswordAsync(user, newPassword));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "ChangePasswordAsync", user.Id.ToString());
Assert.NotEqual(stamp, user.SecurityStamp);
}
@ -365,9 +405,11 @@ namespace Microsoft.AspNet.Identity.Test
{
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
}
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "AddClaimsAsync", user.Id.ToString());
var userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(3, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[0]));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "RemoveClaimsAsync", user.Id.ToString());
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(2, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[1]));
@ -419,6 +461,7 @@ namespace Microsoft.AspNet.Identity.Test
Claim claim = new Claim("c", "b");
Claim oldClaim = userClaims.FirstOrDefault();
IdentityResultAssert.IsSuccess(await manager.ReplaceClaimAsync(user, oldClaim, claim));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "ReplaceClaimAsync", user.Id.ToString());
var newUserClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, newUserClaims.Count);
Claim newClaim = newUserClaims.FirstOrDefault();
@ -463,6 +506,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, "password"));
var result = await manager.ChangePasswordAsync(user, "bogus", "newpassword");
IdentityResultAssert.IsFailure(result, "Incorrect password.");
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "ChangePasswordAsync", user.Id.ToString(), IdentityErrorDescriber.Default.PasswordMismatch());
}
[Fact]
@ -511,6 +555,7 @@ namespace Microsoft.AspNet.Identity.Test
var stamp = user.SecurityStamp;
Assert.NotNull(stamp);
IdentityResultAssert.IsSuccess(await manager.UpdateSecurityStampAsync(user));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "UpdateSecurityStampAsync", user.Id.ToString());
Assert.NotEqual(stamp, user.SecurityStamp);
}
@ -524,6 +569,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, login));
var result = await manager.AddLoginAsync(user, login);
IdentityResultAssert.IsFailure(result, IdentityErrorDescriber.Default.LoginAlreadyAssociated());
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "AddLoginAsync", user.Id.ToString(), IdentityErrorDescriber.Default.LoginAlreadyAssociated());
}
// Email tests
@ -607,7 +653,9 @@ namespace Microsoft.AspNet.Identity.Test
Assert.NotNull(stamp);
var token = await manager.GeneratePasswordResetTokenAsync(user);
Assert.NotNull(token);
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "GeneratePasswordResetTokenAsync", user.Id.ToString());
IdentityResultAssert.IsSuccess(await manager.ResetPasswordAsync(user, token, newPassword));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "ResetPasswordAsync", user.Id.ToString());
Assert.False(await manager.CheckPasswordAsync(user, password));
Assert.True(await manager.CheckPasswordAsync(user, newPassword));
Assert.NotEqual(stamp, user.SecurityStamp);
@ -630,6 +678,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.PasswordValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.ResetPasswordAsync(user, token, newPassword),
AlwaysBadValidator.ErrorMessage);
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "ResetPasswordAsync", user.Id.ToString(), AlwaysBadValidator.ErrorMessage);
Assert.True(await manager.CheckPasswordAsync(user, password));
Assert.Equal(stamp, user.SecurityStamp);
}
@ -647,6 +696,7 @@ namespace Microsoft.AspNet.Identity.Test
var stamp = user.SecurityStamp;
Assert.NotNull(stamp);
IdentityResultAssert.IsFailure(await manager.ResetPasswordAsync(user, "bogus", newPassword), "Invalid token.");
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "ResetPasswordAsync", user.Id.ToString(), IdentityErrorDescriber.Default.InvalidToken());
Assert.True(await manager.CheckPasswordAsync(user, password));
Assert.Equal(stamp, user.SecurityStamp);
}
@ -661,8 +711,14 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2));
var token = await manager.GenerateUserTokenAsync(user, "Static", "test");
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "GenerateUserTokenAsync", user.Id.ToString());
Assert.True(await manager.VerifyUserTokenAsync(user, "Static", "test", token));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "VerifyUserTokenAsync", user.Id.ToString());
Assert.False(await manager.VerifyUserTokenAsync(user, "Static", "test2", token));
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "VerifyUserTokenAsync", user.Id.ToString(), IdentityErrorDescriber.Default.InvalidToken());
Assert.False(await manager.VerifyUserTokenAsync(user, "Static", "test", token + "a"));
Assert.False(await manager.VerifyUserTokenAsync(user2, "Static", "test", token));
}
@ -678,7 +734,9 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
var token = await manager.GenerateEmailConfirmationTokenAsync(user);
Assert.NotNull(token);
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "GenerateEmailConfirmationTokenAsync", user.Id.ToString());
IdentityResultAssert.IsSuccess(await manager.ConfirmEmailAsync(user, token));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "ConfirmEmailAsync", user.Id.ToString());
Assert.True(await manager.IsEmailConfirmedAsync(user));
IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, null));
Assert.False(await manager.IsEmailConfirmedAsync(user));
@ -695,6 +753,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.IsFailure(await manager.ConfirmEmailAsync(user, "bogus"), "Invalid token.");
Assert.False(await manager.IsEmailConfirmedAsync(user));
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "ConfirmEmailAsync", user.Id.ToString(), IdentityErrorDescriber.Default.InvalidToken());
}
[Fact]
@ -770,6 +829,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user));
IdentityResultAssert.IsSuccess(await mgr.ResetAccessFailedCountAsync(user));
IdentityResultAssert.VerifyUserManagerSuccessLog(mgr.Logger, "ResetAccessFailedCountAsync", user.Id.ToString());
Assert.Equal(0, await mgr.GetAccessFailedCountAsync(user));
Assert.False(await mgr.IsLockedOutAsync(user));
Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55));
@ -792,8 +852,10 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await mgr.SetLockoutEnabledAsync(user, true));
Assert.True(await mgr.GetLockoutEnabledAsync(user));
Assert.True(user.LockoutEnabled);
IdentityResultAssert.VerifyUserManagerSuccessLog(mgr.Logger, "SetLockoutEnabledAsync", user.Id.ToString());
Assert.False(await mgr.IsLockedOutAsync(user));
IdentityResultAssert.IsSuccess(await mgr.AccessFailedAsync(user));
IdentityResultAssert.VerifyUserManagerSuccessLog(mgr.Logger, "AccessFailedAsync", user.Id.ToString());
Assert.False(await mgr.IsLockedOutAsync(user));
Assert.False(await mgr.GetLockoutEndDateAsync(user) > DateTimeOffset.UtcNow.AddMinutes(55));
Assert.Equal(1, await mgr.GetAccessFailedCountAsync(user));
@ -814,6 +876,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.True(user.LockoutEnabled);
IdentityResultAssert.IsSuccess(await mgr.SetLockoutEndDateAsync(user, new DateTimeOffset()));
Assert.False(await mgr.IsLockedOutAsync(user));
IdentityResultAssert.VerifyUserManagerSuccessLog(mgr.Logger, "SetLockoutEndDateAsync", user.Id.ToString());
Assert.Equal(new DateTimeOffset(), await mgr.GetLockoutEndDateAsync(user));
Assert.Equal(new DateTimeOffset(), user.LockoutEnd);
}
@ -900,7 +963,7 @@ namespace Microsoft.AspNet.Identity.Test
private class AlwaysBadValidator : IUserValidator<TUser>, IRoleValidator<TRole>,
IPasswordValidator<TUser>
{
public static readonly IdentityError ErrorMessage = new IdentityError { Description = "I'm Bad." };
public static readonly IdentityError ErrorMessage = new IdentityError { Description = "I'm Bad.", Code = "BadValidator" };
public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password, CancellationToken cancellationToken = default(CancellationToken))
{
@ -950,6 +1013,7 @@ namespace Microsoft.AspNet.Identity.Test
manager.RoleValidators.Clear();
manager.RoleValidators.Add(new AlwaysBadValidator());
IdentityResultAssert.IsFailure(await manager.UpdateAsync(role), error);
IdentityResultAssert.VerifyRoleManagerFailureLog(manager.Logger, "UpdateAsync", role.Id.ToString(), AlwaysBadValidator.ErrorMessage);
}
[Fact]
@ -961,6 +1025,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
IdentityResultAssert.IsSuccess(await manager.DeleteAsync(role));
Assert.False(await manager.RoleExistsAsync(role.Name));
IdentityResultAssert.VerifyRoleManagerSuccessLog(manager.Logger, "DeleteAsync", role.Id.ToString());
}
[Fact]
@ -974,6 +1039,7 @@ namespace Microsoft.AspNet.Identity.Test
{
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(role, c));
}
IdentityResultAssert.VerifyRoleManagerSuccessLog(manager.Logger, "AddClaimAsync", role.Id.ToString());
var roleClaims = await manager.GetClaimsAsync(role);
Assert.Equal(3, roleClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(role, claims[0]));
@ -985,6 +1051,8 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(role, claims[2]));
roleClaims = await manager.GetClaimsAsync(role);
Assert.Equal(0, roleClaims.Count);
IdentityResultAssert.VerifyRoleManagerSuccessLog(manager.Logger, "RemoveClaimAsync", role.Id.ToString());
}
[Fact]
@ -1018,6 +1086,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.True(await manager.RoleExistsAsync(role.Name));
IdentityResultAssert.IsSuccess(await manager.SetRoleNameAsync(role, "Changed"));
IdentityResultAssert.IsSuccess(await manager.UpdateAsync(role));
IdentityResultAssert.VerifyRoleManagerSuccessLog(manager.Logger, "UpdateAsync", role.Id.ToString());
Assert.False(await manager.RoleExistsAsync("update"));
Assert.Equal(role, await manager.FindByNameAsync("Changed"));
}
@ -1085,6 +1154,7 @@ namespace Microsoft.AspNet.Identity.Test
var role = CreateRole("dupeRole");
Assert.False(await manager.RoleExistsAsync(role.Name));
IdentityResultAssert.IsSuccess(await manager.CreateAsync(role));
IdentityResultAssert.VerifyRoleManagerSuccessLog(manager.Logger, "CreateAsync", role.Id.ToString());
Assert.True(await manager.RoleExistsAsync(role.Name));
var role2 = CreateRole();
role2.Name = role.Name;
@ -1109,6 +1179,8 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await manager.CreateAsync(u));
IdentityResultAssert.IsSuccess(await manager.AddToRoleAsync(u, role.Name));
Assert.True(await manager.IsInRoleAsync(u, role.Name));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "AddToRoleAsync", u.Id.ToString());
}
}
@ -1161,6 +1233,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.True(await userManager.IsInRoleAsync(user, r.Name));
}
IdentityResultAssert.IsSuccess(await userManager.RemoveFromRoleAsync(user, roles[2].Name));
IdentityResultAssert.VerifyUserManagerSuccessLog(userManager.Logger, "RemoveFromRoleAsync", user.Id.ToString());
Assert.False(await userManager.IsInRoleAsync(user, roles[2].Name));
}
@ -1201,6 +1274,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await roleMgr.CreateAsync(role));
var result = await userMgr.RemoveFromRoleAsync(user, role.Name);
IdentityResultAssert.IsFailure(result, IdentityErrorDescriber.Default.UserNotInRole(role.Name));
IdentityResultAssert.VerifyUserManagerFailureLog(userMgr.Logger, "RemoveFromRoleAsync", user.Id.ToString(), IdentityErrorDescriber.Default.UserNotInRole(role.Name));
}
[Fact]
@ -1216,6 +1290,7 @@ namespace Microsoft.AspNet.Identity.Test
IdentityResultAssert.IsSuccess(await userMgr.AddToRoleAsync(user, role.Name));
Assert.True(await userMgr.IsInRoleAsync(user, role.Name));
IdentityResultAssert.IsFailure(await userMgr.AddToRoleAsync(user, role.Name), IdentityErrorDescriber.Default.UserAlreadyInRole(role.Name));
IdentityResultAssert.VerifyUserManagerFailureLog(userMgr.Logger, "AddToRoleAsync", user.Id.ToString(), IdentityErrorDescriber.Default.UserAlreadyInRole(role.Name));
}
[Fact]
@ -1261,6 +1336,7 @@ namespace Microsoft.AspNet.Identity.Test
var stamp = await manager.GetSecurityStampAsync(user);
var token1 = await manager.GenerateChangePhoneNumberTokenAsync(user, "111-111-1111");
IdentityResultAssert.IsSuccess(await manager.ChangePhoneNumberAsync(user, "111-111-1111", token1));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "ChangePhoneNumberAsync", user.Id.ToString());
Assert.True(await manager.IsPhoneNumberConfirmedAsync(user));
Assert.Equal(await manager.GetPhoneNumberAsync(user), "111-111-1111");
Assert.NotEqual(stamp, user.SecurityStamp);
@ -1277,6 +1353,7 @@ namespace Microsoft.AspNet.Identity.Test
var stamp = await manager.GetSecurityStampAsync(user);
IdentityResultAssert.IsFailure(await manager.ChangePhoneNumberAsync(user, "111-111-1111", "bogus"),
"Invalid token.");
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "ChangePhoneNumberAsync", user.Id.ToString(), IdentityErrorDescriber.Default.InvalidToken());
Assert.False(await manager.IsPhoneNumberConfirmedAsync(user));
Assert.Equal(await manager.GetPhoneNumberAsync(user), "123-456-7890");
Assert.Equal(stamp, user.SecurityStamp);
@ -1308,12 +1385,16 @@ namespace Microsoft.AspNet.Identity.Test
const string num1 = "111-123-4567";
const string num2 = "111-111-1111";
var token1 = await manager.GenerateChangePhoneNumberTokenAsync(user, num1);
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "GenerateChangePhoneNumberTokenAsync", user.Id.ToString());
var token2 = await manager.GenerateChangePhoneNumberTokenAsync(user, num2);
Assert.NotEqual(token1, token2);
Assert.True(await manager.VerifyChangePhoneNumberTokenAsync(user, token1, num1));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "VerifyChangePhoneNumberTokenAsync", user.Id.ToString());
Assert.True(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num2));
Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num1));
Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token1, num2));
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "VerifyChangePhoneNumberTokenAsync", user.Id.ToString(), IdentityErrorDescriber.Default.InvalidToken());
}
[Fact]
@ -1328,6 +1409,7 @@ namespace Microsoft.AspNet.Identity.Test
string newEmail = user.UserName + "@en.vec";
var token1 = await manager.GenerateChangeEmailTokenAsync(user, newEmail);
IdentityResultAssert.IsSuccess(await manager.ChangeEmailAsync(user, newEmail, token1));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "ChangeEmailAsync", user.Id.ToString());
Assert.True(await manager.IsEmailConfirmedAsync(user));
Assert.Equal(await manager.GetEmailAsync(user), newEmail);
Assert.NotEqual(stamp, user.SecurityStamp);
@ -1345,6 +1427,7 @@ namespace Microsoft.AspNet.Identity.Test
var stamp = await manager.GetSecurityStampAsync(user);
IdentityResultAssert.IsFailure(await manager.ChangeEmailAsync(user, "whatevah@foo.barf", "bogus"),
"Invalid token.");
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "ChangeEmailAsync", user.Id.ToString(), IdentityErrorDescriber.Default.InvalidToken());
Assert.False(await manager.IsEmailConfirmedAsync(user));
Assert.Equal(await manager.GetEmailAsync(user), oldEmail);
Assert.Equal(stamp, user.SecurityStamp);
@ -1386,8 +1469,9 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Null(messageService.Message);
IdentityResultAssert.IsSuccess(await manager.NotifyTwoFactorTokenAsync(user, factorId, token));
Assert.NotNull(messageService.Message);
Assert.Equal("Your security code is: "+token, messageService.Message.Body);
Assert.Equal("Your security code is: " + token, messageService.Message.Body);
Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "VerifyTwoFactorTokenAsync", user.Id.ToString());
}
[Fact]
@ -1427,11 +1511,13 @@ namespace Microsoft.AspNet.Identity.Test
Assert.NotNull(stamp);
var token = await manager.GenerateTwoFactorTokenAsync(user, factorId);
Assert.NotNull(token);
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "GenerateTwoFactorTokenAsync", user.Id.ToString());
Assert.Null(messageService.Message);
IdentityResultAssert.IsSuccess(await manager.NotifyTwoFactorTokenAsync(user, factorId, token));
Assert.NotNull(messageService.Message);
Assert.Equal(subject, messageService.Message.Subject);
Assert.Equal(string.Format(body, token), messageService.Message.Body);
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "NotifyTwoFactorTokenAsync", user.Id.ToString());
Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
}
@ -1461,6 +1547,7 @@ namespace Microsoft.AspNet.Identity.Test
var stamp = user.SecurityStamp;
Assert.NotNull(stamp);
IdentityResultAssert.IsSuccess(await manager.SetTwoFactorEnabledAsync(user, true));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "SetTwoFactorEnabledAsync", user.Id.ToString());
Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user));
Assert.True(await manager.GetTwoFactorEnabledAsync(user));
}
@ -1497,7 +1584,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Null(messageService.Message);
IdentityResultAssert.IsSuccess(await manager.NotifyTwoFactorTokenAsync(user, factorId, token));
Assert.NotNull(messageService.Message);
Assert.Equal("Your security code is: "+token, messageService.Message.Body);
Assert.Equal("Your security code is: " + token, messageService.Message.Body);
Assert.True(await manager.VerifyTwoFactorTokenAsync(user, factorId, token));
}
@ -1563,6 +1650,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.NotNull(factors);
Assert.False(factors.Any());
IdentityResultAssert.IsSuccess(await manager.SetPhoneNumberAsync(user, "111-111-1111"));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "SetPhoneNumberAsync", user.Id.ToString());
user.PhoneNumberConfirmed = true;
await manager.UpdateAsync(user);
factors = await manager.GetValidTwoFactorProvidersAsync(user);
@ -1570,6 +1658,7 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Equal(1, factors.Count());
Assert.Equal("Phone", factors[0]);
IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, "test@test.com"));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "SetEmailAsync", user.Id.ToString());
user.EmailConfirmed = true;
await manager.UpdateAsync(user);
factors = await manager.GetValidTwoFactorProvidersAsync(user);
@ -1618,6 +1707,7 @@ namespace Microsoft.AspNet.Identity.Test
user.PhoneNumber = "4251234567";
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
Assert.False(await manager.VerifyTwoFactorTokenAsync(user, "Phone", "bogus"));
IdentityResultAssert.VerifyUserManagerFailureLog(manager.Logger, "VerifyTwoFactorTokenAsync", user.Id.ToString(), IdentityErrorDescriber.Default.InvalidToken());
}
[Fact]
@ -1637,9 +1727,9 @@ namespace Microsoft.AspNet.Identity.Test
// set to a valid value
await userMgr.SetLockoutEndDateAsync(user, DateTimeOffset.Parse("01/01/2014"));
Assert.Equal(DateTimeOffset.Parse("01/01/2014"), await userMgr.GetLockoutEndDateAsync(user));
}
}
[Fact]
[Fact]
public async Task CanGetUsersWithClaims()
{
var manager = CreateManager();
@ -1651,7 +1741,7 @@ namespace Microsoft.AspNet.Identity.Test
if ((i % 2) == 0)
{
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("foo", "bar")));
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("foo", "bar")));
}
}
@ -1680,7 +1770,8 @@ namespace Microsoft.AspNet.Identity.Test
if ((i % 2) == 0)
{
IdentityResultAssert.IsSuccess(await manager.AddToRolesAsync(user, roles.Select(x=>x.Name).AsEnumerable()));
IdentityResultAssert.IsSuccess(await manager.AddToRolesAsync(user, roles.Select(x => x.Name).AsEnumerable()));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "AddToRolesAsync", user.Id.ToString());
}
}
@ -1711,6 +1802,5 @@ namespace Microsoft.AspNet.Identity.Test
}
return roles;
}
}
}