Added deferred logging with scopes

This commit is contained in:
Suhas Joshi 2015-02-05 17:59:35 -08:00
parent a6bf4029aa
commit 6143af8149
20 changed files with 669 additions and 600 deletions

View File

@ -6,7 +6,10 @@ using Microsoft.Data.Entity;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Logging.Console;
#if DNX451
using NLog.Config;
using NLog.Targets;
#endif
namespace IdentitySamples
{
@ -60,8 +63,18 @@ namespace IdentitySamples
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
#if DNX451
var config = new LoggingConfiguration();
// Step 2. Create targets and add them to the configuration
var consoleTarget = new ColoredConsoleTarget();
config.AddTarget("console", consoleTarget);
consoleTarget.Layout = @"${date:format=HH\\:MM\\:ss} ${ndc} ${logger} ${message} ";
var rule1 = new LoggingRule("*", NLog.LogLevel.Debug, consoleTarget);
config.LoggingRules.Add(rule1);
loggerFactory.AddNLog(new global::NLog.LogFactory(config));
#endif
app.UseErrorPage(ErrorPageOptions.ShowAll)
.UseStaticFiles()
.UseIdentity()

View File

@ -1,7 +1,7 @@
@model IdentitySample.Models.LoginViewModel
@using System.Collections.Generic
@using Microsoft.AspNet.Http
@using Microsoft.AspNet.Http.Security
@using Microsoft.AspNet.Http.Authentication
@{
//TODO: Until we have a way to specify the layout page at application level.

View File

@ -20,7 +20,8 @@
"EntityFramework.SqlServer": "7.0.0-*",
"Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*",
"Microsoft.Framework.OptionsModel": "1.0.0-*",
"Microsoft.Framework.Logging.Console": "1.0.0-*"
"Microsoft.Framework.Logging.Console": "1.0.0-*",
"Microsoft.Framework.Logging.NLog": "1.0.0-*"
},
"commands": {
"web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:41532",

View File

@ -0,0 +1,36 @@
// 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.Runtime.CompilerServices;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Identity.Logging
{
public static class IdentityLoggerExtensions
{
private static TResult Log<TResult>(this ILogger logger, TResult result, Func<TResult, LogLevel> getLevel,
Func<string> messageAccessor)
{
var logLevel = getLevel(result);
// Check if log level is enabled before creating the message.
if (logger.IsEnabled(logLevel))
{
logger.Log(logLevel, 0, messageAccessor(), null, (msg, exp) => (string)msg);
}
return result;
}
public static SignInResult Log(this ILogger logger, SignInResult result, [CallerMemberName]string methodName = null)
=> logger.Log(result, r => r.GetLogLevel(), () => Resources.FormatLoggingResult(methodName, result));
public static IdentityResult Log(this ILogger logger, IdentityResult result, [CallerMemberName]string methodName = null)
=> logger.Log(result, r => r.GetLogLevel(), () => Resources.FormatLoggingResult(methodName, result));
public static bool Log(this ILogger logger, bool result, [CallerMemberName]string methodName = null)
=> logger.Log(result, b => b ? LogLevel.Verbose : LogLevel.Warning,
() => Resources.FormatLoggingResult(methodName, result));
}
}

View File

@ -13,9 +13,7 @@ namespace Microsoft.AspNet.Identity
public class IdentityResult
{
private static readonly IdentityResult _success = new IdentityResult { Succeeded = true };
private List<IdentityError> _errors = new List<IdentityError>();
/// <summary>
/// True if the operation was successful
/// </summary>
@ -24,16 +22,13 @@ namespace Microsoft.AspNet.Identity
/// <summary>
/// List of errors
/// </summary>
public IEnumerable<IdentityError> Errors { get { return _errors; } }
public IEnumerable<IdentityError> Errors => _errors;
/// <summary>
/// Static success result
/// </summary>
/// <returns></returns>
public static IdentityResult Success
{
get { return _success; }
}
public static IdentityResult Success => _success;
/// <summary>
/// Failed helper method
@ -51,21 +46,23 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// Log Identity result
/// Return string representation of IdentityResult
/// </summary>
/// <param name="logger"></param>
/// <param name="message"></param>
public virtual void Log(ILogger logger, string message)
/// <returns>"Succedded", if result is suceeded else "Failed:error codes"</returns>
public override string ToString()
{
// TODO: Take logging level as a parameter
if (Succeeded)
{
logger.LogInformation(Resources.FormatLogIdentityResultSuccess(message));
}
else
{
logger.LogWarning(Resources.FormatLogIdentityResultFailure(message, string.Join(",", Errors.Select(x => x.Code).ToList())));
}
return Succeeded ?
"Succeeded" :
string.Format("{0} : {1}", "Failed", string.Join(",", Errors.Select(x => x.Code).ToList()));
}
/// <summary>
/// Get the level to log this result
/// </summary>
/// <returns>LogLevel to log</returns>
public virtual LogLevel GetLogLevel()
{
return Succeeded ? LogLevel.Verbose : LogLevel.Warning;
}
}
}

View File

@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Identity
default:
throw new InvalidOperationException(Resources.InvalidPasswordHasherCompatibilityMode);
}
_rng = options.Rng;
}

View File

@ -651,67 +651,35 @@ namespace Microsoft.AspNet.Identity
}
/// <summary>
/// {0} : Failed : {1}
/// {0} : {1}
/// </summary>
internal static string LogIdentityResultFailure
internal static string LoggingResult
{
get { return GetString("LogIdentityResultFailure"); }
get { return GetString("LoggingResult"); }
}
/// <summary>
/// {0} : Failed : {1}
/// {0} : {1}
/// </summary>
internal static string FormatLogIdentityResultFailure(object p0, object p1)
internal static string FormatLoggingResult(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);
return string.Format(CultureInfo.CurrentCulture, GetString("LoggingResult"), p0, p1);
}
/// <summary>
/// {0} for user: {1}
/// </summary>
internal static string LoggingResultMessage
internal static string LoggingResultMessageForUser
{
get { return GetString("LoggingResultMessage"); }
get { return GetString("LoggingResultMessageForUser"); }
}
/// <summary>
/// {0} for user: {1}
/// </summary>
internal static string FormatLoggingResultMessage(object p0, object p1)
internal static string FormatLoggingResultMessageForUser(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("LoggingResultMessage"), p0, p1);
return string.Format(CultureInfo.CurrentCulture, GetString("LoggingResultMessageForUser"), p0, p1);
}
/// <summary>

View File

@ -277,19 +277,11 @@
<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 name="LoggingResult" xml:space="preserve">
<value>{0} : {1}</value>
<comment>Logging statement for a result object</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">
<data name="LoggingResultMessageForUser" xml:space="preserve">
<value>{0} for user: {1}</value>
<comment>Message prefix for Identity result</comment>
</data>

View File

@ -4,11 +4,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Identity.Logging;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Identity
@ -20,13 +22,17 @@ namespace Microsoft.AspNet.Identity
public class RoleManager<TRole> : IDisposable where TRole : class
{
private bool _disposed;
private HttpContext _context;
private readonly HttpContext _context;
/// <summary>
/// Constructor
/// Constructor
/// </summary>
/// <param name="store">The IRoleStore commits changes via the UpdateAsync/CreateAsync methods</param>
/// <param name="roleValidator"></param>
/// <param name="roleValidators">IEnumerable of role validators</param>
/// <param name="keyNormalizer">user property normalizers</param>
/// <param name="errors">IdentityErrorDescribers</param>
/// <param name="logger">Logger for RoleManager</param>
/// <param name="contextAccessor">HttpContext accessor object</param>
public RoleManager(IRoleStore<TRole> store,
IEnumerable<IRoleValidator<TRole>> roleValidators,
ILookupNormalizer keyNormalizer,
@ -59,6 +65,11 @@ namespace Microsoft.AspNet.Identity
/// </summary>
protected IRoleStore<TRole> Store { get; private set; }
/// <summary>
/// Used for logging results
/// </summary>
protected internal virtual ILogger Logger { get; set; }
/// <summary>
/// Used to validate roles before persisting changes
/// </summary>
@ -69,11 +80,6 @@ namespace Microsoft.AspNet.Identity
/// </summary>
internal IdentityErrorDescriber ErrorDescriber { get; set; }
/// <summary>
/// Used to log results
/// </summary>
internal ILogger Logger { get; set; }
/// <summary>
/// Used to normalize user names, role names, emails for uniqueness
/// </summary>
@ -119,13 +125,7 @@ namespace Microsoft.AspNet.Identity
}
}
private CancellationToken CancellationToken
{
get
{
return _context?.RequestAborted ?? CancellationToken.None;
}
}
private CancellationToken CancellationToken => _context?.RequestAborted ?? CancellationToken.None;
/// <summary>
/// Dispose this object
@ -162,20 +162,23 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("role");
}
var result = await ValidateRoleInternal(role);
if (!result.Succeeded)
{
return result;
}
await UpdateNormalizedRoleNameAsync(role);
return await LogResultAsync(await Store.CreateAsync(role, CancellationToken), role);
result = await Store.CreateAsync(role, CancellationToken);
using (await BeginLoggingScopeAsync(role))
{
return Logger.Log(result);
}
}
/// <summary>
/// Update the user's normalized user name
/// </summary>
/// <param name="user"></param>
/// <param name="role"></param>
/// <returns></returns>
public virtual async Task UpdateNormalizedRoleNameAsync(TRole role)
{
@ -197,7 +200,10 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("role");
}
return await LogResultAsync(await UpdateRoleAsync(role), role);
using (await BeginLoggingScopeAsync(role))
{
return Logger.Log(await UpdateRoleAsync(role));
}
}
private async Task<IdentityResult> UpdateRoleAsync(TRole role)
@ -223,7 +229,11 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("role");
}
return await LogResultAsync(await Store.DeleteAsync(role, CancellationToken), role);
using (await BeginLoggingScopeAsync(role))
{
return Logger.Log(await Store.DeleteAsync(role, CancellationToken));
}
}
/// <summary>
@ -284,9 +294,13 @@ namespace Microsoft.AspNet.Identity
public virtual async Task<IdentityResult> SetRoleNameAsync(TRole role, string name)
{
ThrowIfDisposed();
await Store.SetRoleNameAsync(role, name, CancellationToken);
await UpdateNormalizedRoleNameAsync(role);
return await LogResultAsync(IdentityResult.Success, role);
using (await BeginLoggingScopeAsync(role))
{
await Store.SetRoleNameAsync(role, name, CancellationToken);
await UpdateNormalizedRoleNameAsync(role);
return Logger.Log(IdentityResult.Success);
}
}
/// <summary>
@ -345,8 +359,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("role");
}
await claimStore.AddClaimAsync(role, claim, CancellationToken);
return await LogResultAsync(await UpdateRoleAsync(role), role);
using (await BeginLoggingScopeAsync(role))
{
await claimStore.AddClaimAsync(role, claim, CancellationToken);
return Logger.Log(await UpdateRoleAsync(role));
}
}
/// <summary>
@ -363,8 +381,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("role");
}
await claimStore.RemoveClaimAsync(role, claim, CancellationToken);
return await LogResultAsync(await UpdateRoleAsync(role), role);
using (await BeginLoggingScopeAsync(role))
{
await claimStore.RemoveClaimAsync(role, claim, CancellationToken);
return Logger.Log(await UpdateRoleAsync(role));
}
}
/// <summary>
@ -383,20 +405,12 @@ 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 = "")
protected virtual async Task<IDisposable> BeginLoggingScopeAsync(TRole role, [CallerMemberName] string methodName = null)
{
result.Log(Logger, Resources.FormatLoggingResultMessageForRole(methodName, await GetRoleIdAsync(role)));
return result;
var state = Resources.FormatLoggingResultMessageForRole(methodName, await GetRoleIdAsync(role));
return Logger.BeginScope(state);
}
private void ThrowIfDisposed()
{

View File

@ -4,12 +4,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.AspNet.Identity.Logging;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
@ -31,6 +33,7 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException(nameof(userManager));
}
if (contextAccessor == null || contextAccessor.HttpContext == null)
{
throw new ArgumentNullException(nameof(contextAccessor));
@ -48,29 +51,28 @@ namespace Microsoft.AspNet.Identity
Logger = logger?.CreateLogger<SignInManager<TUser>>() ?? new Logger<SignInManager<TUser>>(new LoggerFactory());
}
protected internal virtual ILogger Logger { get; set; }
internal UserManager<TUser> UserManager { get; private set; }
internal HttpContext Context { get; private set; }
internal IUserClaimsPrincipalFactory<TUser> ClaimsFactory { get; private set; }
internal IdentityOptions Options { get; private set; }
internal ILogger Logger { get; set; }
// Should this be a func?
public virtual async Task<ClaimsPrincipal> CreateUserPrincipalAsync(TUser user)
{
return await ClaimsFactory.CreateAsync(user);
}
public virtual async Task<ClaimsPrincipal> CreateUserPrincipalAsync(TUser user) => await ClaimsFactory.CreateAsync(user);
public virtual async Task<bool> CanSignInAsync(TUser user)
{
if (Options.SignIn.RequireConfirmedEmail && !(await UserManager.IsEmailConfirmedAsync(user)))
{
return await LogResultAsync(false, user);
return Logger.Log(false);
}
if (Options.SignIn.RequireConfirmedPhoneNumber && !(await UserManager.IsPhoneNumberConfirmedAsync(user)))
{
return await LogResultAsync(false, user);
return Logger.Log(false);
}
return await LogResultAsync(true, user);
return Logger.Log(true);
}
public virtual async Task SignInAsync(TUser user, bool isPersistent, string authenticationMethod = null)
@ -149,31 +151,35 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException(nameof(user));
}
var error = await PreSignInCheck(user);
if (error != null)
{
return await LogResultAsync(error, user);
}
if (await IsLockedOut(user))
{
return await LogResultAsync(SignInResult.LockedOut, user);
}
if (await UserManager.CheckPasswordAsync(user, password))
{
await ResetLockout(user);
return await LogResultAsync(await SignInOrTwoFactorAsync(user, isPersistent), user);
}
if (UserManager.SupportsUserLockout && shouldLockout)
{
// If lockout is requested, increment access failed count which might lock out the user
await UserManager.AccessFailedAsync(user);
if (await UserManager.IsLockedOutAsync(user))
{
return await LogResultAsync(SignInResult.LockedOut, user);
using (await BeginLoggingScopeAsync(user))
{
var error = await PreSignInCheck(user);
if (error != null)
{
return Logger.Log(error);
}
if (await IsLockedOut(user))
{
return Logger.Log(SignInResult.LockedOut);
}
if (await UserManager.CheckPasswordAsync(user, password))
{
await ResetLockout(user);
return Logger.Log(await SignInOrTwoFactorAsync(user, isPersistent));
}
if (UserManager.SupportsUserLockout && shouldLockout)
{
// If lockout is requested, increment access failed count which might lock out the user
await UserManager.AccessFailedAsync(user);
if (await UserManager.IsLockedOutAsync(user))
{
return Logger.Log(SignInResult.LockedOut);
}
}
return Logger.Log(SignInResult.Failed);
}
return await LogResultAsync(SignInResult.Failed, user);
}
public virtual async Task<SignInResult> PasswordSignInAsync(string userName, string password,
@ -184,6 +190,7 @@ namespace Microsoft.AspNet.Identity
{
return SignInResult.Failed;
}
return await PasswordSignInAsync(user, password, isPersistent, shouldLockout);
}
@ -205,8 +212,7 @@ namespace Microsoft.AspNet.Identity
public virtual async Task<bool> IsTwoFactorClientRememberedAsync(TUser user)
{
var userId = await UserManager.GetUserIdAsync(user);
var result =
await Context.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme);
var result = await Context.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme);
return (result?.Principal != null && result.Principal.FindFirstValue(ClaimTypes.Name) == userId);
}
@ -239,38 +245,41 @@ namespace Microsoft.AspNet.Identity
{
return SignInResult.Failed;
}
var error = await PreSignInCheck(user);
if (error != null)
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(error, user);
}
if (await UserManager.VerifyTwoFactorTokenAsync(user, provider, code))
{
// When token is verified correctly, clear the access failed count used for lockout
await ResetLockout(user);
// Cleanup external cookie
if (twoFactorInfo.LoginProvider != null)
var error = await PreSignInCheck(user);
if (error != null)
{
Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationScheme);
return Logger.Log(error);
}
await SignInAsync(user, isPersistent, twoFactorInfo.LoginProvider);
if (rememberClient)
if (await UserManager.VerifyTwoFactorTokenAsync(user, provider, code))
{
await RememberTwoFactorClientAsync(user);
// When token is verified correctly, clear the access failed count used for lockout
await ResetLockout(user);
// Cleanup external cookie
if (twoFactorInfo.LoginProvider != null)
{
Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationScheme);
}
await SignInAsync(user, isPersistent, twoFactorInfo.LoginProvider);
if (rememberClient)
{
await RememberTwoFactorClientAsync(user);
}
await UserManager.ResetAccessFailedCountAsync(user);
await SignInAsync(user, isPersistent);
return Logger.Log(SignInResult.Success);
}
await UserManager.ResetAccessFailedCountAsync(user);
await SignInAsync(user, isPersistent);
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);
return Logger.Log(SignInResult.Failed);
}
// If the token is incorrect, record the failure which also may cause the user to be locked out
await UserManager.AccessFailedAsync(user);
return await LogResultAsync(SignInResult.Failed, user);
}
/// <summary>
/// Returns the user who has started the two factor authentication process
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public virtual async Task<TUser> GetTwoFactorAuthenticationUserAsync()
{
@ -290,12 +299,16 @@ namespace Microsoft.AspNet.Identity
{
return SignInResult.Failed;
}
var error = await PreSignInCheck(user);
if (error != null)
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(error, user);
var error = await PreSignInCheck(user);
if (error != null)
{
return Logger.Log(error);
}
return Logger.Log(await SignInOrTwoFactorAsync(user, isPersistent, loginProvider));
}
return await LogResultAsync(await SignInOrTwoFactorAsync(user, isPersistent, loginProvider), user);
}
private const string LoginProviderKey = "LoginProvider";
@ -384,34 +397,12 @@ 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 = "")
protected virtual async Task<IDisposable> BeginLoggingScopeAsync(TUser user, [CallerMemberName] string methodName = null)
{
Logger.LogInformation(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;
var state = Resources.FormatLoggingResultMessageForUser(methodName, await UserManager.GetUserIdAsync(user));
return Logger.BeginScope(state);
}
internal static ClaimsPrincipal StoreTwoFactorInfo(string userId, string loginProvider)
{
@ -423,7 +414,6 @@ namespace Microsoft.AspNet.Identity
}
return new ClaimsPrincipal(identity);
}
internal class TwoFactorAuthenticationInfo
{
public string UserId { get; set; }

View File

@ -40,74 +40,51 @@ namespace Microsoft.AspNet.Identity
/// Static success result
/// </summary>
/// <returns></returns>
public static SignInResult Success
{
get { return _success; }
}
public static SignInResult Success => _success;
/// <summary>
/// Static failure result
/// </summary>
/// <returns></returns>
public static SignInResult Failed
{
get { return _failed; }
}
public static SignInResult Failed => _failed;
/// <summary>
/// Static locked out result
/// </summary>
/// <returns></returns>
public static SignInResult LockedOut
{
get { return _lockedOut; }
}
public static SignInResult LockedOut => _lockedOut;
/// <summary>
/// Static not allowed result
/// </summary>
/// <returns></returns>
public static SignInResult NotAllowed
{
get { return _notAllowed; }
}
public static SignInResult NotAllowed => _notAllowed;
/// <summary>
/// Static two factor required result
/// </summary>
/// <returns></returns>
public static SignInResult TwoFactorRequired
public static SignInResult TwoFactorRequired => _twoFactorRequired;
/// <summary>
/// Returns string representation of the result.
/// </summary>
/// <returns></returns>
public override string ToString()
{
get { return _twoFactorRequired; }
return IsLockedOut ? "Lockedout" :
IsNotAllowed ? "NotAllowed" :
RequiresTwoFactor ? "RequiresTwoFactor" :
Succeeded ? "Succeeded" : "Failed";
}
/// <summary>
/// Log result based on properties
/// Returns the level at which this result should be logged
/// </summary>
/// <param name="logger"></param>
/// <param name="message"></param>
public virtual void Log(ILogger logger, string message)
/// <returns></returns>
public virtual LogLevel GetLogLevel()
{
if (IsLockedOut)
{
logger.LogInformation(Resources.FormatLoggingSigninResult(message, "Lockedout"));
}
else if (IsNotAllowed)
{
logger.LogInformation(Resources.FormatLoggingSigninResult(message, "NotAllowed"));
}
else if (RequiresTwoFactor)
{
logger.LogInformation(Resources.FormatLoggingSigninResult(message, "RequiresTwoFactor"));
}
else if (Succeeded)
{
logger.LogInformation(Resources.FormatLoggingSigninResult(message, "Succeeded"));
}
else
{
logger.LogInformation(Resources.FormatLoggingSigninResult(message, "Failed"));
}
return Succeeded || RequiresTwoFactor ? LogLevel.Verbose : LogLevel.Warning;
}
}
}

View File

@ -5,12 +5,14 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Identity.Logging;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
@ -27,7 +29,7 @@ namespace Microsoft.AspNet.Identity
private TimeSpan _defaultLockout = TimeSpan.Zero;
private bool _disposed;
private HttpContext _context;
private readonly HttpContext _context;
/// <summary>
/// Constructor
@ -40,7 +42,8 @@ namespace Microsoft.AspNet.Identity
/// <param name="keyNormalizer"></param>
/// <param name="errors"></param>
/// <param name="tokenProviders"></param>
/// <param name="loggerFactory"></param>
/// <param name="logger"></param>
/// <param name="contextAccessor"></param>
public UserManager(IUserStore<TUser> store,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TUser> passwordHasher,
@ -94,6 +97,11 @@ namespace Microsoft.AspNet.Identity
/// </summary>
protected internal IUserStore<TUser> Store { get; set; }
/// <summary>
/// Used to log messages
/// </summary>
protected internal virtual ILogger Logger { get; set; }
internal IPasswordHasher<TUser> PasswordHasher { get; set; }
internal IList<IUserValidator<TUser>> UserValidators { get; } = new List<IUserValidator<TUser>>();
@ -104,8 +112,6 @@ namespace Microsoft.AspNet.Identity
internal IdentityErrorDescriber ErrorDescriber { get; set; }
internal ILogger Logger { get; set; }
internal IdentityOptions Options { get; set; }
/// <summary>
@ -244,13 +250,7 @@ namespace Microsoft.AspNet.Identity
}
}
private CancellationToken CancellationToken
{
get
{
return _context?.RequestAborted ?? CancellationToken.None;
}
}
private CancellationToken CancellationToken => _context?.RequestAborted ?? CancellationToken.None;
/// <summary>
/// Dispose the store context
@ -331,7 +331,12 @@ namespace Microsoft.AspNet.Identity
}
await UpdateNormalizedUserNameAsync(user);
await UpdateNormalizedEmailAsync(user);
return await LogResultAsync(await Store.CreateAsync(user, CancellationToken), user);
result = await Store.CreateAsync(user, CancellationToken);
using (await BeginLoggingScopeAsync(user))
{
return Logger.Log(result);
}
}
/// <summary>
@ -346,7 +351,11 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -361,7 +370,11 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
return await LogResultAsync(await Store.DeleteAsync(user, CancellationToken), user);
using (await BeginLoggingScopeAsync(user))
{
return Logger.Log(await Store.DeleteAsync(user, CancellationToken));
}
}
/// <summary>
@ -432,7 +445,7 @@ namespace Microsoft.AspNet.Identity
/// <summary>
/// Normalize a key (user name, email) for uniqueness comparisons
/// </summary>
/// <param name="userName"></param>
/// <param name="key"></param>
/// <returns></returns>
public virtual string NormalizeKey(string key)
{
@ -478,8 +491,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await UpdateUserName(user, userName);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await UpdateUserName(user, userName);
return Logger.Log(await UpdateUserAsync(user));
}
}
private async Task UpdateUserName(TUser user, string userName)
@ -513,14 +530,18 @@ namespace Microsoft.AspNet.Identity
{
return false;
}
var result = await VerifyPasswordAsync(passwordStore, user, password);
if (result == PasswordVerificationResult.SuccessRehashNeeded)
{
await UpdatePasswordHash(passwordStore, user, password, validatePassword: false);
await UpdateUserAsync(user);
}
return await LogResultAsync(result != PasswordVerificationResult.Failed, user);
using (await BeginLoggingScopeAsync(user))
{
var result = await VerifyPasswordAsync(passwordStore, user, password);
if (result == PasswordVerificationResult.SuccessRehashNeeded)
{
Logger.Log(await UpdatePasswordHash(passwordStore, user, password, validatePassword: false));
Logger.Log(await UpdateUserAsync(user));
}
return Logger.Log(result != PasswordVerificationResult.Failed);
}
}
/// <summary>
@ -536,7 +557,11 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
return await LogResultAsync(await passwordStore.HasPasswordAsync(user, CancellationToken), user);
using (await BeginLoggingScopeAsync(user))
{
return Logger.Log(await passwordStore.HasPasswordAsync(user, CancellationToken));
}
}
/// <summary>
@ -553,17 +578,21 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
var hash = await passwordStore.GetPasswordHashAsync(user, CancellationToken);
if (hash != null)
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserAlreadyHasPassword()), user);
var hash = await passwordStore.GetPasswordHashAsync(user, CancellationToken);
if (hash != null)
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.UserAlreadyHasPassword()));
}
var result = await UpdatePasswordHash(passwordStore, user, password);
if (!result.Succeeded)
{
return Logger.Log(result);
}
return Logger.Log(await UpdateUserAsync(user));
}
var result = await UpdatePasswordHash(passwordStore, user, password);
if (!result.Succeeded)
{
return await LogResultAsync(result, user);
}
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -581,23 +610,26 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
if (await VerifyPasswordAsync(passwordStore, user, currentPassword) != PasswordVerificationResult.Failed)
using (await BeginLoggingScopeAsync(user))
{
var result = await UpdatePasswordHash(passwordStore, user, newPassword);
if (!result.Succeeded)
if (await VerifyPasswordAsync(passwordStore, user, currentPassword) != PasswordVerificationResult.Failed)
{
return await LogResultAsync(result, user);
var result = await UpdatePasswordHash(passwordStore, user, newPassword);
if (!result.Succeeded)
{
return Logger.Log(result);
}
return Logger.Log(await UpdateUserAsync(user));
}
return await LogResultAsync(await UpdateUserAsync(user), user);
return Logger.Log(IdentityResult.Failed(ErrorDescriber.PasswordMismatch()));
}
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.PasswordMismatch()), user);
}
/// <summary>
/// Remove a user's password
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> RemovePasswordAsync(TUser user,
CancellationToken cancellationToken = default(CancellationToken))
@ -608,8 +640,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await UpdatePasswordHash(passwordStore, user, null, validatePassword: false);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await UpdatePasswordHash(passwordStore, user, null, validatePassword: false);
return Logger.Log(await UpdateUserAsync(user));
}
}
internal async Task<IdentityResult> UpdatePasswordHash(IUserPasswordStore<TUser> passwordStore,
@ -682,8 +718,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await UpdateSecurityStampInternal(user);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await UpdateSecurityStampInternal(user);
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -694,9 +734,13 @@ namespace Microsoft.AspNet.Identity
public virtual async Task<string> GeneratePasswordResetTokenAsync(TUser user)
{
ThrowIfDisposed();
var token = await GenerateUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword");
await LogResultAsync(IdentityResult.Success, user);
return token;
using (await BeginLoggingScopeAsync(user))
{
var token = await GenerateUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword");
Logger.Log(IdentityResult.Success);
return token;
}
}
/// <summary>
@ -713,18 +757,22 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
// Make sure the token is valid and the stamp matches
if (!await VerifyUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword", token))
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
// Make sure the token is valid and the stamp matches
if (!await VerifyUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword", token))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.InvalidToken()));
}
var passwordStore = GetPasswordStore();
var result = await UpdatePasswordHash(passwordStore, user, newPassword);
if (!result.Succeeded)
{
return Logger.Log(result);
}
return Logger.Log(await UpdateUserAsync(user));
}
var passwordStore = GetPasswordStore();
var result = await UpdatePasswordHash(passwordStore, user, newPassword);
if (!result.Succeeded)
{
return await LogResultAsync(result, user);
}
return await LogResultAsync(await UpdateUserAsync(user), user);
}
// Update the security stamp if the store supports it
@ -777,7 +825,8 @@ namespace Microsoft.AspNet.Identity
/// Remove a user login
/// </summary>
/// <param name="user"></param>
/// <param name="login"></param>
/// <param name="loginProvider"></param>
/// <param name="providerKey"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> RemoveLoginAsync(TUser user, string loginProvider, string providerKey)
{
@ -795,9 +844,13 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await loginStore.RemoveLoginAsync(user, loginProvider, providerKey, CancellationToken);
await UpdateSecurityStampInternal(user);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await loginStore.RemoveLoginAsync(user, loginProvider, providerKey, CancellationToken);
await UpdateSecurityStampInternal(user);
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -818,13 +871,17 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
var existingUser = await FindByLoginAsync(login.LoginProvider, login.ProviderKey);
if (existingUser != null)
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.LoginAlreadyAssociated()), user);
var existingUser = await FindByLoginAsync(login.LoginProvider, login.ProviderKey);
if (existingUser != null)
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.LoginAlreadyAssociated()));
}
await loginStore.AddLoginAsync(user, login, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
await loginStore.AddLoginAsync(user, login, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -893,8 +950,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await claimStore.AddClaimsAsync(user, claims, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await claimStore.AddClaimsAsync(user, claims, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -920,8 +981,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await claimStore.ReplaceClaimAsync(user, claim, newClaim, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await claimStore.ReplaceClaimAsync(user, claim, newClaim, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -963,8 +1028,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("claims");
}
await claimStore.RemoveClaimsAsync(user, claims, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await claimStore.RemoveClaimsAsync(user, claims, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -1007,13 +1076,17 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
var userRoles = await userRoleStore.GetRolesAsync(user, CancellationToken);
if (userRoles.Contains(role))
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role)), user);
var userRoles = await userRoleStore.GetRolesAsync(user, CancellationToken);
if (userRoles.Contains(role))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role)));
}
await userRoleStore.AddToRoleAsync(user, role, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
await userRoleStore.AddToRoleAsync(user, role, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1034,16 +1107,20 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("roles");
}
var userRoles = await userRoleStore.GetRolesAsync(user, CancellationToken);
foreach (var role in roles)
using (await BeginLoggingScopeAsync(user))
{
if (userRoles.Contains(role))
var userRoles = await userRoleStore.GetRolesAsync(user, CancellationToken);
foreach (var role in roles)
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role)), user);
if (userRoles.Contains(role))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.UserAlreadyInRole(role)));
}
await userRoleStore.AddToRoleAsync(user, role, CancellationToken);
}
await userRoleStore.AddToRoleAsync(user, role, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1060,12 +1137,16 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
if (!await userRoleStore.IsInRoleAsync(user, role, CancellationToken))
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserNotInRole(role)), user);
if (!await userRoleStore.IsInRoleAsync(user, role, CancellationToken))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.UserNotInRole(role)));
}
await userRoleStore.RemoveFromRoleAsync(user, role, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
await userRoleStore.RemoveFromRoleAsync(user, role, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1086,15 +1167,19 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("roles");
}
foreach (var role in roles)
using (await BeginLoggingScopeAsync(user))
{
if (!await userRoleStore.IsInRoleAsync(user, role, CancellationToken))
foreach (var role in roles)
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserNotInRole(role)), user);
if (!await userRoleStore.IsInRoleAsync(user, role, CancellationToken))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.UserNotInRole(role)));
}
await userRoleStore.RemoveFromRoleAsync(user, role, CancellationToken);
}
await userRoleStore.RemoveFromRoleAsync(user, role, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1171,10 +1256,14 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await store.SetEmailAsync(user, email, CancellationToken);
await store.SetEmailConfirmedAsync(user, false, CancellationToken);
await UpdateSecurityStampInternal(user);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await store.SetEmailAsync(user, email, CancellationToken);
await store.SetEmailConfirmedAsync(user, false, CancellationToken);
await UpdateSecurityStampInternal(user);
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -1217,9 +1306,13 @@ namespace Microsoft.AspNet.Identity
public async virtual Task<string> GenerateEmailConfirmationTokenAsync(TUser user)
{
ThrowIfDisposed();
var token = await GenerateUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "Confirmation");
await LogResultAsync(IdentityResult.Success, user);
return token;
using (await BeginLoggingScopeAsync(user))
{
var token = await GenerateUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "Confirmation");
Logger.Log(IdentityResult.Success);
return token;
}
}
/// <summary>
@ -1236,12 +1329,16 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
if (!await VerifyUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "Confirmation", token))
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
if (!await VerifyUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "Confirmation", token))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.InvalidToken()));
}
await store.SetEmailConfirmedAsync(user, true, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
await store.SetEmailConfirmedAsync(user, true, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1269,13 +1366,18 @@ namespace Microsoft.AspNet.Identity
/// Generate a change email token for the user using the UserTokenProvider
/// </summary>
/// <param name="user"></param>
/// <param name="newEmail"></param>
/// <returns></returns>
public virtual async Task<string> GenerateChangeEmailTokenAsync(TUser user, string newEmail)
{
ThrowIfDisposed();
var token = await GenerateUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail));
await LogResultAsync(IdentityResult.Success, user);
return token;
using (await BeginLoggingScopeAsync(user))
{
var token = await GenerateUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail));
Logger.Log(IdentityResult.Success);
return token;
}
}
/// <summary>
@ -1283,7 +1385,7 @@ namespace Microsoft.AspNet.Identity
/// </summary>
/// <param name="user"></param>
/// <param name="token"></param>
/// <param name="newPassword"></param>
/// <param name="newEmail"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> ChangeEmailAsync(TUser user, string newEmail, string token)
{
@ -1292,16 +1394,20 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
// Make sure the token is valid and the stamp matches
if (!await VerifyUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail), token))
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
// Make sure the token is valid and the stamp matches
if (!await VerifyUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail), token))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.InvalidToken()));
}
var store = GetEmailStore();
await store.SetEmailAsync(user, newEmail, CancellationToken);
await store.SetEmailConfirmedAsync(user, true, CancellationToken);
await UpdateSecurityStampInternal(user);
return Logger.Log(await UpdateUserAsync(user));
}
var store = GetEmailStore();
await store.SetEmailAsync(user, newEmail, CancellationToken);
await store.SetEmailConfirmedAsync(user, true, CancellationToken);
await UpdateSecurityStampInternal(user);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
// IUserPhoneNumberStore methods
@ -1345,10 +1451,14 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await store.SetPhoneNumberAsync(user, phoneNumber, CancellationToken);
await store.SetPhoneNumberConfirmedAsync(user, false, CancellationToken);
await UpdateSecurityStampInternal(user);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await store.SetPhoneNumberAsync(user, phoneNumber, CancellationToken);
await store.SetPhoneNumberConfirmedAsync(user, false, CancellationToken);
await UpdateSecurityStampInternal(user);
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -1366,14 +1476,18 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
if (!await VerifyChangePhoneNumberTokenAsync(user, token, phoneNumber))
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
if (!await VerifyChangePhoneNumberTokenAsync(user, token, phoneNumber))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.InvalidToken()));
}
await store.SetPhoneNumberAsync(user, phoneNumber, CancellationToken);
await store.SetPhoneNumberConfirmedAsync(user, true, CancellationToken);
await UpdateSecurityStampInternal(user);
return Logger.Log(await UpdateUserAsync(user));
}
await store.SetPhoneNumberAsync(user, phoneNumber, CancellationToken);
await store.SetPhoneNumberConfirmedAsync(user, true, CancellationToken);
await UpdateSecurityStampInternal(user);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1407,11 +1521,15 @@ namespace Microsoft.AspNet.Identity
public virtual async Task<string> GenerateChangePhoneNumberTokenAsync(TUser user, string phoneNumber)
{
ThrowIfDisposed();
var token = Rfc6238AuthenticationService.GenerateCode(
await CreateSecurityTokenAsync(user), phoneNumber)
.ToString(CultureInfo.InvariantCulture);
await LogResultAsync(IdentityResult.Success, user);
return token;
using (await BeginLoggingScopeAsync(user))
{
var token = Rfc6238AuthenticationService.GenerateCode(
await CreateSecurityTokenAsync(user), phoneNumber)
.ToString(CultureInfo.InvariantCulture);
Logger.Log(IdentityResult.Success);
return token;
}
}
/// <summary>
@ -1424,24 +1542,29 @@ namespace Microsoft.AspNet.Identity
public virtual async Task<bool> VerifyChangePhoneNumberTokenAsync(TUser user, string token, string phoneNumber)
{
ThrowIfDisposed();
var securityToken = await CreateSecurityTokenAsync(user);
int code;
if (securityToken != null && Int32.TryParse(token, out code))
using (await BeginLoggingScopeAsync(user))
{
if (Rfc6238AuthenticationService.ValidateCode(securityToken, code, phoneNumber))
var securityToken = await CreateSecurityTokenAsync(user);
int code;
if (securityToken != null && Int32.TryParse(token, out code))
{
await LogResultAsync(IdentityResult.Success, user);
return true;
if (Rfc6238AuthenticationService.ValidateCode(securityToken, code, phoneNumber))
{
Logger.Log(IdentityResult.Success);
return true;
}
}
Logger.Log(IdentityResult.Failed(ErrorDescriber.InvalidToken()));
return false;
}
await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
return false;
}
/// <summary>
/// Verify a user token with the specified purpose
/// </summary>
/// <param name="user"></param>
/// <param name="tokenProvider"></param>
/// <param name="purpose"></param>
/// <param name="token"></param>
/// <returns></returns>
@ -1456,23 +1579,27 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException(nameof(tokenProvider));
}
if (!_tokenProviders.ContainsKey(tokenProvider))
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.NoTokenProvider, tokenProvider));
}
// Make sure the token is valid
var result = await _tokenProviders[tokenProvider].ValidateAsync(purpose, token, this, user);
if (result)
using (await BeginLoggingScopeAsync(user))
{
await LogResultAsync(IdentityResult.Success, user);
}
else
{
await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
}
if (!_tokenProviders.ContainsKey(tokenProvider))
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.NoTokenProvider, tokenProvider));
}
// Make sure the token is valid
var result = await _tokenProviders[tokenProvider].ValidateAsync(purpose, token, this, user);
return result;
if (result)
{
Logger.Log(IdentityResult.Success);
}
else
{
Logger.Log(IdentityResult.Failed(ErrorDescriber.InvalidToken()));
}
return result;
}
}
/// <summary>
@ -1480,6 +1607,7 @@ namespace Microsoft.AspNet.Identity
/// </summary>
/// <param name="purpose"></param>
/// <param name="user"></param>
/// <param name="tokenProvider"></param>
/// <returns></returns>
public virtual async Task<string> GenerateUserTokenAsync(TUser user, string tokenProvider, string purpose)
{
@ -1497,8 +1625,9 @@ namespace Microsoft.AspNet.Identity
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.NoTokenProvider, tokenProvider));
}
//TODO: Should we scope here ?
var token = await _tokenProviders[tokenProvider].GenerateAsync(purpose, this, user);
await LogResultAsync(IdentityResult.Success, user);
Logger.Log(IdentityResult.Success);
return token;
}
@ -1543,7 +1672,7 @@ namespace Microsoft.AspNet.Identity
/// Verify a user token with the specified provider
/// </summary>
/// <param name="user"></param>
/// <param name="twoFactorProvider"></param>
/// <param name="tokenProvider"></param>
/// <param name="token"></param>
/// <returns></returns>
public virtual async Task<bool> VerifyTwoFactorTokenAsync(TUser user, string tokenProvider, string token)
@ -1558,24 +1687,28 @@ namespace Microsoft.AspNet.Identity
throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture,
Resources.NoTokenProvider, tokenProvider));
}
// Make sure the token is valid
var result = await _tokenProviders[tokenProvider].ValidateAsync("TwoFactor", token, this, user);
if (result)
using (await BeginLoggingScopeAsync(user))
{
await LogResultAsync(IdentityResult.Success, user);
// Make sure the token is valid
var result = await _tokenProviders[tokenProvider].ValidateAsync("TwoFactor", token, this, user);
if (result)
{
Logger.Log(IdentityResult.Success);
}
else
{
Logger.Log(IdentityResult.Failed(ErrorDescriber.InvalidToken()));
}
return result;
}
else
{
await LogResultAsync(IdentityResult.Failed(ErrorDescriber.InvalidToken()), user);
}
return result;
}
/// <summary>
/// Get a user token for a specific user factor provider
/// </summary>
/// <param name="user"></param>
/// <param name="twoFactorProvider"></param>
/// <param name="tokenProvider"></param>
/// <returns></returns>
public virtual async Task<string> GenerateTwoFactorTokenAsync(TUser user, string tokenProvider)
{
@ -1589,9 +1722,13 @@ namespace Microsoft.AspNet.Identity
throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture,
Resources.NoTokenProvider, tokenProvider));
}
var token = await _tokenProviders[tokenProvider].GenerateAsync("TwoFactor", this, user);
await LogResultAsync(IdentityResult.Success, user);
return token;
using (await BeginLoggingScopeAsync(user))
{
var token = await _tokenProviders[tokenProvider].GenerateAsync("TwoFactor", this, user);
Logger.Log(IdentityResult.Success);
return token;
}
}
// IUserFactorStore methods
@ -1635,9 +1772,13 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await store.SetTwoFactorEnabledAsync(user, enabled, CancellationToken);
await UpdateSecurityStampInternal(user);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await store.SetTwoFactorEnabledAsync(user, enabled, CancellationToken);
await UpdateSecurityStampInternal(user);
return Logger.Log(await UpdateUserAsync(user));
}
}
// IUserLockoutStore methods
@ -1686,8 +1827,12 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
await store.SetLockoutEnabledAsync(user, enabled, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
using (await BeginLoggingScopeAsync(user))
{
await store.SetLockoutEnabledAsync(user, enabled, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
}
/// <summary>
@ -1736,12 +1881,16 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
if (!await store.GetLockoutEnabledAsync(user, CancellationToken))
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(IdentityResult.Failed(ErrorDescriber.UserLockoutNotEnabled()), user);
if (!await store.GetLockoutEnabledAsync(user, CancellationToken))
{
return Logger.Log(IdentityResult.Failed(ErrorDescriber.UserLockoutNotEnabled()));
}
await store.SetLockoutEndDateAsync(user, lockoutEnd, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
await store.SetLockoutEndDateAsync(user, lockoutEnd, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1759,16 +1908,20 @@ namespace Microsoft.AspNet.Identity
{
throw new ArgumentNullException("user");
}
// If this puts the user over the threshold for lockout, lock them out and reset the access failed count
var count = await store.IncrementAccessFailedCountAsync(user, CancellationToken);
if (count < Options.Lockout.MaxFailedAccessAttempts)
using (await BeginLoggingScopeAsync(user))
{
return await LogResultAsync(await UpdateUserAsync(user), user);
// If this puts the user over the threshold for lockout, lock them out and reset the access failed count
var count = await store.IncrementAccessFailedCountAsync(user, CancellationToken);
if (count < Options.Lockout.MaxFailedAccessAttempts)
{
return Logger.Log(await UpdateUserAsync(user));
}
await store.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.Add(Options.Lockout.DefaultLockoutTimeSpan),
CancellationToken);
await store.ResetAccessFailedCountAsync(user, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
await store.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.Add(Options.Lockout.DefaultLockoutTimeSpan),
CancellationToken);
await store.ResetAccessFailedCountAsync(user, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1785,13 +1938,15 @@ namespace Microsoft.AspNet.Identity
throw new ArgumentNullException("user");
}
if (await GetAccessFailedCountAsync(user) == 0)
using (await BeginLoggingScopeAsync(user))
{
return IdentityResult.Success;
if (await GetAccessFailedCountAsync(user) == 0)
{
return Logger.Log(IdentityResult.Success);
}
await store.ResetAccessFailedCountAsync(user, CancellationToken);
return Logger.Log(await UpdateUserAsync(user));
}
await store.ResetAccessFailedCountAsync(user, CancellationToken);
return await LogResultAsync(await UpdateUserAsync(user), user);
}
/// <summary>
@ -1824,7 +1979,7 @@ namespace Microsoft.AspNet.Identity
/// <summary>
/// Get all the users in a role
/// </summary>
/// <param name="role"></param>
/// <param name="roleName"></param>
/// <returns></returns>
public virtual Task<IList<TUser>> GetUsersInRoleAsync(string roleName)
{
@ -1838,42 +1993,12 @@ 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 = "")
protected virtual async Task<IDisposable> BeginLoggingScopeAsync(TUser user, [CallerMemberName] string methodName = null)
{
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.LogInformation(string.Format("{0} : {1}", baseMessage, result.ToString()));
}
else
{
Logger.LogWarning(string.Format("{0} : {1}", baseMessage, result.ToString()));
}
return result;
var state = Resources.FormatLoggingResultMessageForUser(methodName, await GetUserIdAsync(user));
return Logger.BeginScope(state);
}
private void ThrowIfDisposed()
{

View File

@ -24,29 +24,5 @@ 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<IdentityResult>(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<IdentityResult>(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Failed : Foo,Bar", logMessage.ToString());
}
}
}

View File

@ -129,7 +129,8 @@ namespace Microsoft.AspNet.Identity.Test
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, null);
helper.Logger = logger.Object;
string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "Lockedout");
string expectedScope = string.Format("{0} for {1}: {2}", "PasswordSignInAsync", "user", user.Id);
string expectedLog = string.Format("{0} : {1}", "PasswordSignInAsync", "Lockedout");
// Act
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
@ -137,7 +138,8 @@ namespace Microsoft.AspNet.Identity.Test
// Assert
Assert.False(result.Succeeded);
Assert.True(result.IsLockedOut);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedLog));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedScope));
manager.Verify();
}
@ -178,14 +180,16 @@ namespace Microsoft.AspNet.Identity.Test
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, null);
helper.Logger = logger.Object;
string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "Succeeded");
string expectedScope = string.Format("{0} for {1}: {2}", "PasswordSignInAsync", "user", user.Id);
string expectedLog = string.Format("{0} : {1}", "PasswordSignInAsync", "Succeeded");
// Act
var result = await helper.PasswordSignInAsync(user.UserName, "password", isPersistent, false);
// Assert
Assert.True(result.Succeeded);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedLog));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedScope));
manager.Verify();
context.Verify();
response.Verify();
@ -264,13 +268,14 @@ namespace Microsoft.AspNet.Identity.Test
options.Setup(a => a.Options).Returns(identityOptions);
var logStore = new StringBuilder();
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
var helper = new SignInManager<TestUser>(manager.Object,
contextAccessor.Object,
new UserClaimsPrincipalFactory<TestUser, TestRole>(manager.Object, roleManager.Object, options.Object),
options.Object,
var helper = new SignInManager<TestUser>(manager.Object,
contextAccessor.Object,
new UserClaimsPrincipalFactory<TestUser, TestRole>(manager.Object, roleManager.Object, options.Object),
options.Object,
null);
helper.Logger = logger.Object;
string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id, "RequiresTwoFactor");
string expectedScope = string.Format("{0} for {1}: {2}", "PasswordSignInAsync", "user", user.Id);
string expectedLog = string.Format("{0} : {1}", "PasswordSignInAsync", "RequiresTwoFactor");
// Act
var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false);
@ -278,7 +283,8 @@ namespace Microsoft.AspNet.Identity.Test
// Assert
Assert.False(result.Succeeded);
Assert.True(result.RequiresTwoFactor);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedLog));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedScope));
manager.Verify();
context.Verify();
response.Verify();
@ -320,14 +326,16 @@ namespace Microsoft.AspNet.Identity.Test
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, null);
helper.Logger = logger.Object;
string expected = string.Format("{0} for user: {1} : Result : {2}", "ExternalLoginSignInAsync", user.Id.ToString(), "Succeeded");
string expectedScope = string.Format("{0} for {1}: {2}", "ExternalLoginSignInAsync", "user", user.Id);
string expectedLog = string.Format("{0} : {1}", "ExternalLoginSignInAsync", "Succeeded");
// Act
var result = await helper.ExternalLoginSignInAsync(loginProvider, providerKey, isPersistent);
// Assert
Assert.True(result.Succeeded);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedLog));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedScope));
manager.Verify();
context.Verify();
response.Verify();
@ -405,14 +413,16 @@ namespace Microsoft.AspNet.Identity.Test
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory, options.Object, null);
helper.Logger = logger.Object;
string expected = string.Format("{0} for user: {1} : Result : {2}", "TwoFactorSignInAsync", user.Id.ToString(), "Succeeded");
string expectedScope = string.Format("{0} for {1}: {2}", "TwoFactorSignInAsync", "user", user.Id);
string expectedLog = string.Format("{0} : {1}", "TwoFactorSignInAsync", "Succeeded");
// Act
var result = await helper.TwoFactorSignInAsync(provider, code, isPersistent, rememberClient);
// Assert
Assert.True(result.Succeeded);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedLog));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedScope));
manager.Verify();
context.Verify();
response.Verify();
@ -559,13 +569,15 @@ namespace Microsoft.AspNet.Identity.Test
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
helper.Logger = logger.Object;
string expected = string.Format("{0} for user: {1} : Result : {2}", "PasswordSignInAsync", user.Id.ToString(), "Failed");
string expectedScope = string.Format("{0} for {1}: {2}", "PasswordSignInAsync", "user", user.Id);
string expectedLog = string.Format("{0} : {1}", "PasswordSignInAsync", "Failed");
// Act
var result = await helper.PasswordSignInAsync(user.UserName, "bogus", false, false);
// Assert
Assert.False(result.Succeeded);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedLog));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedScope));
manager.Verify();
context.Verify();
contextAccessor.Verify();
@ -664,7 +676,8 @@ namespace Microsoft.AspNet.Identity.Test
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
helper.Logger = logger.Object;
string expected = string.Format("{0} for user: {1} : Result : {2}", "CanSignInAsync", user.Id.ToString(), confirmed.ToString());
string expectedScope = string.Format("{0} for {1}: {2}", "PasswordSignInAsync", "user", user.Id);
string expectedLog = string.Format("{0} : {1}", "CanSignInAsync", confirmed.ToString());
// Act
var result = await helper.PasswordSignInAsync(user, "password", false, false);
@ -673,7 +686,9 @@ namespace Microsoft.AspNet.Identity.Test
Assert.Equal(confirmed, result.Succeeded);
Assert.NotEqual(confirmed, result.IsNotAllowed);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedLog));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedScope));
manager.Verify();
context.Verify();
response.Verify();
@ -683,7 +698,7 @@ namespace Microsoft.AspNet.Identity.Test
private static void SetupSignIn(Mock<HttpResponse> response, string userId = null, bool? isPersistent = null, string loginProvider = null)
{
response.Setup(r => r.SignIn(IdentityOptions.ApplicationCookieAuthenticationScheme,
It.Is<ClaimsPrincipal>(id =>
It.Is<ClaimsPrincipal>(id =>
(userId == null || id.FindFirstValue(ClaimTypes.NameIdentifier) == userId) &&
(loginProvider == null || id.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider)),
It.Is<AuthenticationProperties>(v => isPersistent == null || v.IsPersistent == isPersistent))).Verifiable();
@ -719,7 +734,8 @@ namespace Microsoft.AspNet.Identity.Test
var logger = MockHelpers.MockILogger<SignInManager<TestUser>>(logStore);
var helper = new SignInManager<TestUser>(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object, null);
helper.Logger = logger.Object;
string expected = string.Format("{0} for user: {1} : Result : {2}", "CanSignInAsync", user.Id.ToString(), confirmed.ToString());
string expectedScope = string.Format("{0} for {1}: {2}", "PasswordSignInAsync", "user", user.Id);
string expectedLog = string.Format("{0} : {1}", "CanSignInAsync", confirmed.ToString());
// Act
var result = await helper.PasswordSignInAsync(user, "password", false, false);
@ -727,7 +743,8 @@ namespace Microsoft.AspNet.Identity.Test
// Assert
Assert.Equal(confirmed, result.Succeeded);
Assert.NotEqual(confirmed, result.IsNotAllowed);
Assert.NotEqual(-1, logStore.ToString().IndexOf(expected));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedLog));
Assert.NotEqual(-1, logStore.ToString().IndexOf(expectedScope));
manager.Verify();
context.Verify();
response.Verify();

View File

@ -1,71 +0,0 @@
// 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<SignInResultTest>(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<SignInResultTest>(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<SignInResultTest>(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<SignInResultTest>(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<SignInResultTest>(logMessage);
result.Log(logger.Object, "Operation");
Assert.Equal("Operation : Result : Failed", logMessage.ToString());
}
}
}

View File

@ -420,6 +420,10 @@ namespace Microsoft.AspNet.Identity.Test
store.Setup(s => s.GetPasswordHashAsync(user, CancellationToken.None))
.ReturnsAsync(hashed)
.Verifiable();
store.Setup(x => x.GetUserIdAsync(It.IsAny<TestUser>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(Guid.NewGuid().ToString()));
store.Setup(x => x.UpdateAsync(It.IsAny<TestUser>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(IdentityResult.Success));
hasher.Setup(s => s.VerifyHashedPassword(user, hashed, pwd)).Returns(PasswordVerificationResult.SuccessRehashNeeded).Verifiable();
hasher.Setup(s => s.HashPassword(user, pwd)).Returns(rehashed).Verifiable();
var userManager = MockHelpers.TestUserManager(store.Object);
@ -540,7 +544,9 @@ namespace Microsoft.AspNet.Identity.Test
[Fact]
public async Task SecurityStampMethodsFailWhenStoreNotImplemented()
{
var manager = MockHelpers.TestUserManager(new NoopUserStore());
var store = new Mock<IUserStore<IdentityUser>>();
store.Setup(x => x.GetUserIdAsync(It.IsAny<IdentityUser>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(Guid.NewGuid().ToString()));
var manager = MockHelpers.TestUserManager(store.Object);
Assert.False(manager.SupportsUserSecurityStamp);
await Assert.ThrowsAsync<NotSupportedException>(() => manager.UpdateSecurityStampAsync(null));
await Assert.ThrowsAsync<NotSupportedException>(() => manager.GetSecurityStampAsync(null));

View File

@ -62,8 +62,10 @@ namespace Microsoft.AspNet.Identity.Test
TestLogger testlogger = logger as TestLogger;
if (testlogger != null)
{
string expected = string.Format("{0} for {1}: {2} : Success", methodName, userOrRole, id);
Assert.True(testlogger.LogMessages.Contains(expected));
string expectedScope = string.Format("{0} for {1}: {2}", methodName, userOrRole, id);
string expectedLog = string.Format("{0} : Succeeded", methodName);
Assert.True(testlogger.LogMessages.Contains(expectedScope));
Assert.True(testlogger.LogMessages.Contains(expectedLog));
}
else
{
@ -84,15 +86,17 @@ namespace Microsoft.AspNet.Identity.Test
}
}
private static void VerifyFailureLog(ILogger logger, string className, string methodName, string userId, string userOrRole = "user", params IdentityError[] errors)
private static void VerifyFailureLog(ILogger logger, string className, string methodName, string id, string userOrRole = "user", params IdentityError[] errors)
{
TestLogger testlogger = logger as TestLogger;
if (testlogger != null)
{
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()));
string expectedScope = string.Format("{0} for {1}: {2}", methodName, userOrRole, id);
string expectedLog = string.Format("{0} : Failed : {1}", methodName, string.Join(",", errors.Select(x => x.Code).ToList()));
Assert.True(testlogger.LogMessages.Contains(expected));
Assert.True(testlogger.LogMessages.Contains(expectedScope));
Assert.True(testlogger.LogMessages.Contains(expectedLog));
}
else
{

View File

@ -42,8 +42,23 @@ namespace Microsoft.AspNet.Identity.Test
logger.Setup(x => x.Log(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);
{
if (formatter == null)
{
logStore.Append(state.ToString());
}
else
{
logStore.Append(formatter(state, exception));
}
logStore.Append(" ");
});
logger.Setup(x => x.BeginScope(It.IsAny<object>())).Callback((object state) =>
{
logStore.Append(state.ToString());
logStore.Append(" ");
});
logger.Setup(x => x.IsEnabled(LogLevel.Verbose)).Returns(true);
logger.Setup(x => x.IsEnabled(LogLevel.Warning)).Returns(true);
return logger;
@ -75,8 +90,8 @@ 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 RoleManager<TRole>(store, roles,
new UpperInvariantLookupNormalizer(),
return new RoleManager<TRole>(store, roles,
new UpperInvariantLookupNormalizer(),
new IdentityErrorDescriber(),
null,
null);

View File

@ -13,7 +13,8 @@ namespace Microsoft.AspNet.Identity.Test
public IDisposable BeginScope(object state)
{
throw new NotImplementedException();
LogMessages.Add(state?.ToString());
return null;
}
public bool IsEnabled(LogLevel logLevel)
@ -23,7 +24,14 @@ namespace Microsoft.AspNet.Identity.Test
public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
LogMessages.Add(state.ToString());
if (formatter == null)
{
LogMessages.Add(state.ToString());
}
else
{
LogMessages.Add(formatter(state, exception));
}
}
}
}

View File

@ -141,13 +141,13 @@ 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());
string expectedLog = string.Format("{0} : {1}", "CheckPasswordAsync", 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());
expectedLog = string.Format("{0} : {1}", "CheckPasswordAsync", false.ToString());
IdentityResultAssert.VerifyLogMessage(manager.Logger, expectedLog);
Assert.True(await manager.CheckPasswordAsync(user, "New"));
}
@ -708,7 +708,8 @@ 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());
var expectedLog = string.Format("{0} : {1}", "GenerateUserTokenAsync", "Succeeded");
IdentityResultAssert.VerifyLogMessage(manager.Logger, expectedLog);
Assert.True(await manager.VerifyUserTokenAsync(user, "Static", "test", token));
IdentityResultAssert.VerifyUserManagerSuccessLog(manager.Logger, "VerifyUserTokenAsync", user.Id.ToString());