Merge branch 'release/2.2'

This commit is contained in:
Nate McMaster 2018-07-10 12:54:00 -07:00
commit 913f8bcd4e
No known key found for this signature in database
GPG Key ID: A778D9601BD78810
2 changed files with 79 additions and 15 deletions

View File

@ -89,7 +89,8 @@ namespace Microsoft.AspNetCore.Identity
/// <summary> /// <summary>
/// The <see cref="HttpContext"/> used. /// The <see cref="HttpContext"/> used.
/// </summary> /// </summary>
public HttpContext Context { public HttpContext Context
{
get get
{ {
var context = _context ?? _contextAccessor?.HttpContext; var context = _context ?? _contextAccessor?.HttpContext;
@ -330,7 +331,13 @@ namespace Microsoft.AspNetCore.Identity
if (await UserManager.CheckPasswordAsync(user, password)) if (await UserManager.CheckPasswordAsync(user, password))
{ {
await ResetLockout(user); var alwaysLockout = AppContext.TryGetSwitch("Microsoft.AspNetCore.Identity.CheckPasswordSignInAlwaysResetLockoutOnSuccess", out var enabled) && enabled;
// Only reset the lockout when TFA is not enabled when not in quirks mode
if (alwaysLockout || !await IsTfaEnabled(user))
{
await ResetLockout(user);
}
return SignInResult.Success; return SignInResult.Success;
} }
Logger.LogWarning(2, "User {userId} failed to provide the correct password.", await UserManager.GetUserIdAsync(user)); Logger.LogWarning(2, "User {userId} failed to provide the correct password.", await UserManager.GetUserIdAsync(user));
@ -709,6 +716,11 @@ namespace Microsoft.AspNetCore.Identity
return identity; return identity;
} }
private async Task<bool> IsTfaEnabled(TUser user)
=> UserManager.SupportsUserTwoFactor &&
await UserManager.GetTwoFactorEnabledAsync(user) &&
(await UserManager.GetValidTwoFactorProvidersAsync(user)).Count > 0;
/// <summary> /// <summary>
/// Signs in the specified <paramref name="user"/> if <paramref name="bypassTwoFactor"/> is set to false. /// Signs in the specified <paramref name="user"/> if <paramref name="bypassTwoFactor"/> is set to false.
/// Otherwise stores the <paramref name="user"/> for use after a two factor check. /// Otherwise stores the <paramref name="user"/> for use after a two factor check.
@ -720,10 +732,7 @@ namespace Microsoft.AspNetCore.Identity
/// <returns>Returns a <see cref="SignInResult"/></returns> /// <returns>Returns a <see cref="SignInResult"/></returns>
protected virtual async Task<SignInResult> SignInOrTwoFactorAsync(TUser user, bool isPersistent, string loginProvider = null, bool bypassTwoFactor = false) protected virtual async Task<SignInResult> SignInOrTwoFactorAsync(TUser user, bool isPersistent, string loginProvider = null, bool bypassTwoFactor = false)
{ {
if (!bypassTwoFactor && if (!bypassTwoFactor && await IsTfaEnabled(user))
UserManager.SupportsUserTwoFactor &&
await UserManager.GetTwoFactorEnabledAsync(user) &&
(await UserManager.GetValidTwoFactorProvidersAsync(user)).Count > 0)
{ {
if (!await IsTwoFactorClientRememberedAsync(user)) if (!await IsTwoFactorClientRememberedAsync(user))
{ {

View File

@ -266,6 +266,64 @@ namespace Microsoft.AspNetCore.Identity.Test
auth.Verify(); auth.Verify();
} }
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task CheckPasswordOnlyResetLockoutWhenTfaNotEnabled(bool tfaEnabled)
{
// Setup
var user = new PocoUser { UserName = "Foo" };
var manager = SetupUserManager(user);
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
manager.Setup(m => m.SupportsUserTwoFactor).Returns(tfaEnabled).Verifiable();
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
if (tfaEnabled)
{
manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable();
manager.Setup(m => m.GetValidTwoFactorProvidersAsync(user)).ReturnsAsync(new string[1] {"Fake"}).Verifiable();
}
else
{
manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable();
}
var context = new DefaultHttpContext();
var helper = SetupSignInManager(manager.Object, context);
// Act
var result = await helper.CheckPasswordSignInAsync(user, "password", false);
// Assert
Assert.True(result.Succeeded);
manager.Verify();
}
[Fact]
public async Task CheckPasswordAlwaysResetLockoutWhenQuirked()
{
AppContext.SetSwitch("Microsoft.AspNetCore.Identity.CheckPasswordSignInAlwaysResetLockoutOnSuccess", true);
// Setup
var user = new PocoUser { UserName = "Foo" };
var manager = SetupUserManager(user);
manager.Setup(m => m.SupportsUserLockout).Returns(true).Verifiable();
manager.Setup(m => m.IsLockedOutAsync(user)).ReturnsAsync(false).Verifiable();
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable();
var context = new DefaultHttpContext();
var helper = SetupSignInManager(manager.Object, context);
// Act
var result = await helper.CheckPasswordSignInAsync(user, "password", false);
// Assert
Assert.True(result.Succeeded);
manager.Verify();
}
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [InlineData(false)]
@ -285,10 +343,7 @@ namespace Microsoft.AspNetCore.Identity.Test
manager.Setup(m => m.SupportsUserTwoFactor).Returns(true).Verifiable(); manager.Setup(m => m.SupportsUserTwoFactor).Returns(true).Verifiable();
manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable(); manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable();
manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable();
if (supportsLockout) manager.Setup(m => m.GetValidTwoFactorProvidersAsync(user)).ReturnsAsync(new string[1] { "Fake" }).Verifiable();
{
manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable();
}
var context = new DefaultHttpContext(); var context = new DefaultHttpContext();
var helper = SetupSignInManager(manager.Object, context); var helper = SetupSignInManager(manager.Object, context);
var auth = MockAuth(context); var auth = MockAuth(context);