diff --git a/src/Microsoft.AspNet.Identity/IdentityResult.cs b/src/Microsoft.AspNet.Identity/IdentityResult.cs
index dd3fe07de6..043c605fef 100644
--- a/src/Microsoft.AspNet.Identity/IdentityResult.cs
+++ b/src/Microsoft.AspNet.Identity/IdentityResult.cs
@@ -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;
}
+
+ ///
+ /// Log Identity result
+ ///
+ ///
+ ///
+ 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())));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj b/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj
index 2c8bf644b8..61c02b9a59 100644
--- a/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj
+++ b/src/Microsoft.AspNet.Identity/Microsoft.AspNet.Identity.kproj
@@ -13,6 +13,9 @@
2.0
+
+ True
+
diff --git a/src/Microsoft.AspNet.Identity/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Identity/Properties/Resources.Designer.cs
index 11169b63ea..2aa5369096 100644
--- a/src/Microsoft.AspNet.Identity/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Identity/Properties/Resources.Designer.cs
@@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Identity
}
///
- /// Security Code
+ /// Security code
///
internal static string DefaultEmailTokenProviderSubject
{
@@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Identity
}
///
- /// Security Code
+ /// Security code
///
internal static string FormatDefaultEmailTokenProviderSubject()
{
@@ -123,7 +123,7 @@ namespace Microsoft.AspNet.Identity
}
///
- /// DefaultTokenProvider
+ /// Default Token Provider
///
internal static string DefaultTokenProvider
{
@@ -131,7 +131,7 @@ namespace Microsoft.AspNet.Identity
}
///
- /// DefaultTokenProvider
+ /// Default Token Provider
///
internal static string FormatDefaultTokenProvider()
{
@@ -155,7 +155,7 @@ namespace Microsoft.AspNet.Identity
}
///
- /// Role Name '{0}' is already taken.
+ /// Role name '{0}' is already taken.
///
internal static string DuplicateRoleName
{
@@ -163,7 +163,7 @@ namespace Microsoft.AspNet.Identity
}
///
- /// Role Name '{0}' is already taken.
+ /// Role name '{0}' is already taken.
///
internal static string FormatDuplicateRoleName(object p0)
{
@@ -171,7 +171,7 @@ namespace Microsoft.AspNet.Identity
}
///
- /// UserName '{0}' is already taken.
+ /// User name '{0}' is already taken.
///
internal static string DuplicateUserName
{
@@ -179,7 +179,7 @@ namespace Microsoft.AspNet.Identity
}
///
- /// UserName '{0}' is already taken.
+ /// User name '{0}' is already taken.
///
internal static string FormatDuplicateUserName(object p0)
{
@@ -746,6 +746,86 @@ namespace Microsoft.AspNet.Identity
return string.Format(CultureInfo.CurrentCulture, GetString("UserNotInRole"), p0);
}
+ ///
+ /// {0} : Failed : {1}
+ ///
+ internal static string LogIdentityResultFailure
+ {
+ get { return GetString("LogIdentityResultFailure"); }
+ }
+
+ ///
+ /// {0} : Failed : {1}
+ ///
+ internal static string FormatLogIdentityResultFailure(object p0, object p1)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("LogIdentityResultFailure"), p0, p1);
+ }
+
+ ///
+ /// {0} : Success
+ ///
+ internal static string LogIdentityResultSuccess
+ {
+ get { return GetString("LogIdentityResultSuccess"); }
+ }
+
+ ///
+ /// {0} : Success
+ ///
+ internal static string FormatLogIdentityResultSuccess(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("LogIdentityResultSuccess"), p0);
+ }
+
+ ///
+ /// {0} : Result : {1}
+ ///
+ internal static string LoggingSigninResult
+ {
+ get { return GetString("LoggingSigninResult"); }
+ }
+
+ ///
+ /// {0} : Result : {1}
+ ///
+ internal static string FormatLoggingSigninResult(object p0, object p1)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("LoggingSigninResult"), p0, p1);
+ }
+
+ ///
+ /// {0} for user: {1}
+ ///
+ internal static string LoggingResultMessage
+ {
+ get { return GetString("LoggingResultMessage"); }
+ }
+
+ ///
+ /// {0} for user: {1}
+ ///
+ internal static string FormatLoggingResultMessage(object p0, object p1)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("LoggingResultMessage"), p0, p1);
+ }
+
+ ///
+ /// {0} for role: {1}
+ ///
+ internal static string LoggingResultMessageForRole
+ {
+ get { return GetString("LoggingResultMessageForRole"); }
+ }
+
+ ///
+ /// {0} for role: {1}
+ ///
+ 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);
diff --git a/src/Microsoft.AspNet.Identity/Resources.resx b/src/Microsoft.AspNet.Identity/Resources.resx
index 2592527afb..2351b1e7aa 100644
--- a/src/Microsoft.AspNet.Identity/Resources.resx
+++ b/src/Microsoft.AspNet.Identity/Resources.resx
@@ -130,7 +130,7 @@
Default name for the email token provider
- Security Code
+ Security code
Default subject for the email
@@ -146,24 +146,24 @@
Default name for the phone number token provider
- DefaultTokenProvider
+ Default Token Provider
Name of the default token provider
Email '{0}' is already taken.
- error for duplicate emails
+ Error for duplicate emails
- Role Name '{0}' is already taken.
- error for duplicate usernames
+ Role name '{0}' is already taken.
+ Error for duplicate user names
- UserName '{0}' is already taken.
- error for duplicate usernames
+ User name '{0}' is already taken.
+ Error for duplicate user names
Email '{0}' is invalid.
- invalid email
+ Invalid email
The provided PasswordHasherCompatibilityMode is invalid.
@@ -175,7 +175,7 @@
Role name '{0}' is invalid.
- error for invalid role names
+ Error for invalid role names
Invalid token.
@@ -183,7 +183,7 @@
User name '{0}' is invalid, can only contain letters or digits.
- usernames can only contain letters or digits
+ User names can only contain letters or digits
A user with this login already exists.
@@ -223,63 +223,63 @@
Role {0} does not exist.
- error when a role does not exist
+ Error when a role does not exist
Store does not implement IQueryableRoleStore<TRole>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IQueryableUserStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IRoleClaimStore<TRole>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserClaimStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserConfirmationStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserEmailStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserLockoutStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserLoginStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserPasswordStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserPhoneNumberStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserRoleStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserSecurityStampStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
Store does not implement IUserTwoFactorStore<TUser>.
- error when the store does not implement this interface
+ Error when the store does not implement this interface
User already has a password set.
- error when AddPasswordAsync called when a user already has a password
+ Error when AddPasswordAsync called when a user already has a password
User already in role '{0}'.
@@ -291,14 +291,34 @@
Lockout is not enabled for this user.
- error when lockout is not enabled
+ Error when lockout is not enabled
User {0} does not exist.
- error when a user does not exist
+ Error when a user does not exist
User is not in role '{0}'.
Error when a user is not in the role
+
+ {0} : Failed : {1}
+ Logging method execution failure
+
+
+ {0} : Success
+ Logging method execution success
+
+
+ {0} : Result : {1}
+ Logging statement for SignInManager
+
+
+ {0} for user: {1}
+ Message prefix for Identity result
+
+
+ {0} for role: {1}
+ Message prefix for Identity result for role operation
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Identity/RoleManager.cs b/src/Microsoft.AspNet.Identity/RoleManager.cs
index 7b23ca8ab2..98b7db3990 100644
--- a/src/Microsoft.AspNet.Identity/RoleManager.cs
+++ b/src/Microsoft.AspNet.Identity/RoleManager.cs
@@ -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
///
/// The IRoleStore commits changes via the UpdateAsync/CreateAsync methods
///
- public RoleManager(IRoleStore store,
+ public RoleManager(IRoleStore store,
IEnumerable> 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));
}
///
@@ -60,6 +65,11 @@ namespace Microsoft.AspNet.Identity
///
public IdentityErrorDescriber ErrorDescriber { get; set; }
+ ///
+ /// Used to log results
+ ///
+ public ILogger Logger { get; set; }
+
///
/// Used to normalize user names, role names, emails for uniqueness
///
@@ -134,7 +144,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task CreateAsync(TRole role,
+ public virtual async Task 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);
}
///
@@ -172,7 +182,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task UpdateAsync(TRole role,
+ public virtual async Task 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 UpdateRoleAsync(TRole role,
+ CancellationToken cancellationToken = default(CancellationToken))
+ {
var result = await ValidateRoleInternal(role, cancellationToken);
if (!result.Succeeded)
{
@@ -196,7 +212,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task DeleteAsync(TRole role,
+ public virtual async Task 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);
}
///
@@ -213,7 +229,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task RoleExistsAsync(string roleName,
+ public virtual async Task RoleExistsAsync(string roleName,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@@ -242,7 +258,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task FindByIdAsync(string roleId,
+ public virtual async Task FindByIdAsync(string roleId,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@@ -255,7 +271,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task GetRoleNameAsync(TRole role,
+ public virtual async Task GetRoleNameAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@@ -269,13 +285,13 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task SetRoleNameAsync(TRole role, string name,
+ public virtual async Task 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);
}
///
@@ -284,7 +300,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task GetRoleIdAsync(TRole role,
+ public virtual async Task GetRoleIdAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@@ -297,7 +313,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task FindByNameAsync(string roleName,
+ public virtual async Task FindByNameAsync(string roleName,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@@ -327,7 +343,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task AddClaimAsync(TRole role, Claim claim,
+ public virtual async Task 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);
}
///
@@ -351,7 +367,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task RemoveClaimAsync(TRole role, Claim claim,
+ public virtual async Task 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);
}
///
@@ -370,7 +386,7 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual async Task> GetClaimsAsync(TRole role,
+ public virtual async Task> GetClaimsAsync(TRole role,
CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
@@ -382,6 +398,21 @@ namespace Microsoft.AspNet.Identity
return await claimStore.GetClaimsAsync(role, cancellationToken);
}
+ ///
+ /// Logs the current Identity Result and returns result object
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected async Task 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)
diff --git a/src/Microsoft.AspNet.Identity/SignInManager.cs b/src/Microsoft.AspNet.Identity/SignInManager.cs
index fb170b95e7..d6fd276950 100644
--- a/src/Microsoft.AspNet.Identity/SignInManager.cs
+++ b/src/Microsoft.AspNet.Identity/SignInManager.cs
@@ -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
///
public class SignInManager where TUser : class
{
- public SignInManager(UserManager userManager,
- IHttpContextAccessor contextAccessor,
- IClaimsIdentityFactory claimsFactory,
- IOptions optionsAccessor = null)
+ public SignInManager(UserManager userManager,
+ IHttpContextAccessor contextAccessor,
+ IClaimsIdentityFactory claimsFactory,
+ IOptions 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));
}
public UserManager UserManager { get; private set; }
public HttpContext Context { get; private set; }
public IClaimsIdentityFactory ClaimsFactory { get; private set; }
public IdentityOptions Options { get; private set; }
+ public ILogger Logger { get; set; }
// Should this be a func?
public virtual async Task 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 PasswordSignInAsync(TUser user, string password,
+ public virtual async Task 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 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 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);
}
///
@@ -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 GetExternalLoginInfoAsync(string expectedXsrf = null,
+ public virtual async Task 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 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;
}
+ ///
+ /// Log boolean result for user and return result
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected async virtual Task 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;
+ }
+
+ ///
+ /// Log SignInStatus for user and return SignInStatus
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected async virtual Task 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);
diff --git a/src/Microsoft.AspNet.Identity/SignInResult.cs b/src/Microsoft.AspNet.Identity/SignInResult.cs
index 9c88817de2..7ef69a60bb 100644
--- a/src/Microsoft.AspNet.Identity/SignInResult.cs
+++ b/src/Microsoft.AspNet.Identity/SignInResult.cs
@@ -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
{
///
@@ -78,5 +80,34 @@ namespace Microsoft.AspNet.Identity
{
get { return _twoFactorRequired; }
}
+
+ ///
+ /// Log result based on properties
+ ///
+ ///
+ ///
+ 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"));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Identity/UserManager.cs b/src/Microsoft.AspNet.Identity/UserManager.cs
index e7897a7e1a..fa63e7d5ff 100644
--- a/src/Microsoft.AspNet.Identity/UserManager.cs
+++ b/src/Microsoft.AspNet.Identity/UserManager.cs
@@ -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
///
///
///
- public UserManager(IUserStore store,
+ ///
+ public UserManager(IUserStore store,
IOptions optionsAccessor = null,
- IPasswordHasher passwordHasher = null,
+ IPasswordHasher passwordHasher = null,
IEnumerable> userValidators = null,
- IEnumerable> passwordValidators = null,
+ IEnumerable> passwordValidators = null,
ILookupNormalizer keyNormalizer = null,
IdentityErrorDescriber errors = null,
- IEnumerable> tokenProviders = null,
- IEnumerable msgProviders = null)
+ IEnumerable> tokenProviders = null,
+ IEnumerable msgProviders = null,
+ ILoggerFactory loggerFactory = null)
{
if (store == null)
{
@@ -60,6 +63,7 @@ namespace Microsoft.AspNet.Identity
PasswordHasher = passwordHasher ?? new PasswordHasher();
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));
+
if (tokenProviders != null)
{
foreach (var tokenProvider in tokenProviders)
@@ -138,6 +146,11 @@ namespace Microsoft.AspNet.Identity
///
public IdentityErrorDescriber ErrorDescriber { get; set; }
+ ///
+ /// Used to log IdentityResult
+ ///
+ 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 GenerateConcurrencyStampAsync(TUser user,
+ public virtual Task GenerateConcurrencyStampAsync(TUser user,
CancellationToken token = default(CancellationToken))
{
return Task.FromResult(Guid.NewGuid().ToString());
}
+ ///
+ /// Validate user and update. Called by other UserManager methods
+ ///
+ ///
+ ///
+ ///
+ private async Task 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);
+ }
+
///
/// Create a user with no password
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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 UpdatePasswordHash(IUserPasswordStore 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);
}
///
@@ -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;
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -1321,11 +1351,14 @@ namespace Microsoft.AspNet.Identity
///
///
///
- public virtual Task GenerateEmailConfirmationTokenAsync(TUser user,
+ public async virtual Task 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;
}
///
@@ -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);
}
///
@@ -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;
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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;
}
///
@@ -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;
}
///
@@ -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;
}
///
@@ -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;
}
///
@@ -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;
}
///
@@ -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
///
///
///
- public virtual async Task SendMessageAsync(string messageProvider, IdentityMessage message,
+ public virtual async Task 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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -2026,6 +2099,44 @@ namespace Microsoft.AspNet.Identity
return store.GetUsersInRoleAsync(roleName, cancellationToken);
}
+ ///
+ /// Logs the current Identity Result and returns result object
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected async Task LogResultAsync(IdentityResult result,
+ TUser user, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "")
+ {
+ result.Log(Logger, Resources.FormatLoggingResultMessage(methodName, await GetUserIdAsync(user)));
+
+ return result;
+ }
+
+ ///
+ /// Logs result of operation being true/false
+ ///
+ ///
+ ///
+ ///
+ /// result
+ protected async Task 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)
diff --git a/src/Microsoft.AspNet.Identity/project.json b/src/Microsoft.AspNet.Identity/project.json
index 0ef1603874..ad83945ac3 100644
--- a/src/Microsoft.AspNet.Identity/project.json
+++ b/src/Microsoft.AspNet.Identity/project.json
@@ -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": {},
diff --git a/test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test/InMemoryEFUserStoreTest.cs b/test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test/InMemoryEFUserStoreTest.cs
index 66c01e5998..758e799ff9 100644
--- a/test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test/InMemoryEFUserStoreTest.cs
+++ b/test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test/InMemoryEFUserStoreTest.cs
@@ -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
+ public class InMemoryEFUserStoreTest : UserManagerTestBase,IDisposable
{
protected override object CreateTestContext()
{
@@ -23,5 +24,10 @@ namespace Microsoft.AspNet.Identity.EntityFramework.InMemory.Test
var store = new RoleStore((InMemoryContext)context);
services.AddInstance>(store);
}
+
+ public void Dispose()
+ {
+ loggerFactory.Dispose();
+ }
}
}
diff --git a/test/Microsoft.AspNet.Identity.EntityFramework.Test/SqlStoreTestBase.cs b/test/Microsoft.AspNet.Identity.EntityFramework.Test/SqlStoreTestBase.cs
index b7e52134aa..3b6aca6f78 100644
--- a/test/Microsoft.AspNet.Identity.EntityFramework.Test/SqlStoreTestBase.cs
+++ b/test/Microsoft.AspNet.Identity.EntityFramework.Test/SqlStoreTestBase.cs
@@ -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()
diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs
index 9fbc2536dc..7cca942833 100644
--- a/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs
+++ b/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs
@@ -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
+ public class InMemoryStoreTest : UserManagerTestBase, IDisposable
{
protected override object CreateTestContext()
{
@@ -22,5 +23,10 @@ namespace Microsoft.AspNet.Identity.InMemory.Test
{
services.AddSingleton, InMemoryRoleStore>();
}
+
+ public void Dispose()
+ {
+ loggerFactory.Dispose();
+ }
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs b/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs
index 488fcc7545..ee4b210d7b 100644
--- a/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs
+++ b/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs
@@ -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
{
- public MyUserManager(IUserStore store) : base(store) { }
+ public MyUserManager(IUserStore store) : base(store) { }
}
private class MyRoleManager : RoleManager
{
public MyRoleManager(IRoleStore store,
- IEnumerable> roleValidators) : base(store, roleValidators)
+ IEnumerable> roleValidators) : base(store)
{
}
diff --git a/test/Microsoft.AspNet.Identity.Test/IdentityResultTest.cs b/test/Microsoft.AspNet.Identity.Test/IdentityResultTest.cs
index 7d24b52bce..f65ab23cfb 100644
--- a/test/Microsoft.AspNet.Identity.Test/IdentityResultTest.cs
+++ b/test/Microsoft.AspNet.Identity.Test/IdentityResultTest.cs
@@ -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());
+ }
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Identity.Test/Microsoft.AspNet.Identity.Test.kproj b/test/Microsoft.AspNet.Identity.Test/Microsoft.AspNet.Identity.Test.kproj
index 1bbfe3ac3e..3c06d031ab 100644
--- a/test/Microsoft.AspNet.Identity.Test/Microsoft.AspNet.Identity.Test.kproj
+++ b/test/Microsoft.AspNet.Identity.Test/Microsoft.AspNet.Identity.Test.kproj
@@ -1,4 +1,4 @@
-
+
14.0
@@ -14,4 +14,9 @@
2.0
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Identity.Test/RoleManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/RoleManagerTest.cs
index cab11a83df..99e35a31fb 100644
--- a/test/Microsoft.AspNet.Identity.Test/RoleManagerTest.cs
+++ b/test/Microsoft.AspNet.Identity.Test/RoleManagerTest.cs
@@ -124,7 +124,7 @@ namespace Microsoft.AspNet.Identity.Test
public async Task RoleManagerPublicNullChecks()
{
Assert.Throws("store",
- () => new RoleManager(null, null));
+ () => new RoleManager(null, null, null));
var manager = CreateRoleManager(new NotImplementedStore());
await Assert.ThrowsAsync("role", async () => await manager.CreateAsync(null));
await Assert.ThrowsAsync("role", async () => await manager.UpdateAsync(null));
@@ -150,7 +150,7 @@ namespace Microsoft.AspNet.Identity.Test
{
var v = new List>();
v.Add(new RoleValidator());
- return new RoleManager(roleStore, v);
+ return new RoleManager(roleStore);
}
private class NotImplementedStore : IRoleStore
diff --git a/test/Microsoft.AspNet.Identity.Test/RoleValidatorTest.cs b/test/Microsoft.AspNet.Identity.Test/RoleValidatorTest.cs
index 75a84c24cb..f1b0aa48fa 100644
--- a/test/Microsoft.AspNet.Identity.Test/RoleValidatorTest.cs
+++ b/test/Microsoft.AspNet.Identity.Test/RoleValidatorTest.cs
@@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Identity.Test
{
// Setup
var validator = new RoleValidator();
- var manager = new RoleManager(new NoopRoleStore(), null);
+ var manager = new RoleManager(new NoopRoleStore());
// Act
// Assert
@@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Identity.Test
{
// Setup
var validator = new RoleValidator();
- var manager = new RoleManager(new NoopRoleStore(), null);
+ var manager = new RoleManager(new NoopRoleStore());
var user = new TestRole {Name = input};
// Act
diff --git a/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs b/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs
index 1528665dde..4bad958493 100644
--- a/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs
+++ b/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs
@@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Identity.Test
var contextAccessor = new Mock();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock>(userManager.Object,
- contextAccessor.Object, claimsManager.Object, options.Object);
+ contextAccessor.Object, claimsManager.Object, options.Object, null);
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), 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();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock>(userManager.Object,
- contextAccessor.Object, claimsManager.Object, options.Object);
+ contextAccessor.Object, claimsManager.Object, options.Object, null);
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), 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();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock>(userManager.Object,
- contextAccessor.Object, claimsManager.Object, options.Object);
+ contextAccessor.Object, claimsManager.Object, options.Object, null);
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), 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();
contextAccessor.Setup(a => a.Value).Returns(httpContext.Object);
var signInManager = new Mock>(userManager.Object,
- contextAccessor.Object, claimsManager.Object, options.Object);
+ contextAccessor.Object, claimsManager.Object, options.Object, null);
signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny(), 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();
diff --git a/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs
index 7d1d1d6c90..401d4cf384 100644
--- a/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs
+++ b/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs
@@ -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("userManager", () => new SignInManager(null, null, null, null));
+ Assert.Throws("userManager", () => new SignInManager(null, null, null, null, null));
var userManager = MockHelpers.MockUserManager().Object;
Assert.Throws("contextAccessor", () => new SignInManager(userManager, null, null, null));
var contextAccessor = new Mock();
@@ -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();
var contextAccessor = new Mock();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
@@ -125,7 +128,10 @@ namespace Microsoft.AspNet.Identity.Test
var options = new Mock>();
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object);
- var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(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();
var response = new Mock();
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>(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(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(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();
var response = new Mock();
response.Setup(r => r.SignIn(It.IsAny(), It.IsAny())).Verifiable();
@@ -245,7 +260,10 @@ namespace Microsoft.AspNet.Identity.Test
var identityOptions = new IdentityOptions();
var options = new Mock>();
options.Setup(a => a.Options).Returns(identityOptions);
- var helper = new SignInManager(manager.Object, contextAccessor.Object, new ClaimsIdentityFactory(manager.Object, roleManager.Object, options.Object), options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(manager.Object, contextAccessor.Object, new ClaimsIdentityFactory(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();
var response = new Mock();
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>(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(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(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(manager.Object, contextAccessor.Object, claimsFactory, options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(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>(manager.Object, roleManager.Object, options.Object);
- var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(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();
var contextAccessor = new Mock();
contextAccessor.Setup(a => a.Value).Returns(context.Object);
@@ -526,12 +557,16 @@ namespace Microsoft.AspNet.Identity.Test
var options = new Mock>();
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object);
- var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(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();
var response = new Mock();
if (confirmed)
@@ -627,7 +663,10 @@ namespace Microsoft.AspNet.Identity.Test
var options = new Mock>();
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object);
- var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(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();
- 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();
var response = new Mock();
if (confirmed)
@@ -664,11 +705,14 @@ namespace Microsoft.AspNet.Identity.Test
contextAccessor.Setup(a => a.Value).Returns(context.Object);
var roleManager = MockHelpers.MockRoleManager();
var identityOptions = new IdentityOptions();
- identityOptions.SignIn.RequireConfirmedEmail = true;
+ identityOptions.SignIn.RequireConfirmedPhoneNumber = true;
var options = new Mock>();
options.Setup(a => a.Options).Returns(identityOptions);
var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object);
- var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object);
+ var logStore = new StringBuilder();
+ var loggerFactory = MockHelpers.MockILoggerFactory(MockHelpers.MockILogger(logStore).Object);
+ var helper = new SignInManager(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();
diff --git a/test/Microsoft.AspNet.Identity.Test/SignInResultTest.cs b/test/Microsoft.AspNet.Identity.Test/SignInResultTest.cs
new file mode 100644
index 0000000000..ce7a522937
--- /dev/null
+++ b/test/Microsoft.AspNet.Identity.Test/SignInResultTest.cs
@@ -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());
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs
index e4cf94ecd5..62f1e77917 100644
--- a/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs
+++ b/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs
@@ -175,7 +175,7 @@ namespace Microsoft.AspNet.Identity.Test
{
// Setup
var store = new Mock>();
- 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(store.Object);
@@ -192,7 +192,7 @@ namespace Microsoft.AspNet.Identity.Test
{
// Setup
var store = new Mock>();
- 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>();
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("store",
- () => new UserManager(null));
+ () => new UserManager(null, null));
var manager = new UserManager(store);
@@ -682,7 +682,7 @@ namespace Microsoft.AspNet.Identity.Test
await Assert.ThrowsAsync("user",
async () => await manager.AddClaimAsync(null, new Claim("a", "b")));
await Assert.ThrowsAsync("user",
- async () => await manager.AddLoginAsync(null, new UserLoginInfo("","","")));
+ async () => await manager.AddLoginAsync(null, new UserLoginInfo("", "", "")));
await Assert.ThrowsAsync("user",
async () => await manager.AddPasswordAsync(null, null));
await Assert.ThrowsAsync("user",
diff --git a/test/Shared/IdentityResultAssert.cs b/test/Shared/IdentityResultAssert.cs
index 617e5c0c6b..907aacecb1 100644
--- a/test/Shared/IdentityResultAssert.cs
+++ b/test/Shared/IdentityResultAssert.cs
@@ -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");
+ }
+ }
}
}
\ No newline at end of file
diff --git a/test/Shared/MockHelpers.cs b/test/Shared/MockHelpers.cs
index f70541bec0..36f2690c60 100644
--- a/test/Shared/MockHelpers.cs
+++ b/test/Shared/MockHelpers.cs
@@ -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> MockUserManager() where TUser : class
{
var store = new Mock>();
- var mgr = new Mock>(store.Object, null, null, null, null, null, null, null, null);
+ var mgr = new Mock>(store.Object, null, null, null, null, null, null, null, null, null);
mgr.Object.UserValidators.Add(new UserValidator());
mgr.Object.PasswordValidators.Add(new PasswordValidator());
return mgr;
@@ -25,7 +29,37 @@ namespace Microsoft.AspNet.Identity.Test
store = store ?? new Mock>().Object;
var roles = new List>();
roles.Add(new RoleValidator());
- return new Mock>(store, roles, null, null);
+ return new Mock>(store, roles, null, null,null);
+ }
+
+ public static Mock MockILogger(StringBuilder logStore = null)
+ {
+ logStore = logStore ?? LogMessage;
+ var logger = new Mock();
+ logger.Setup(x => x.Write(It.IsAny(), It.IsAny(), It.IsAny