diff --git a/src/Identity/Core/src/SignInManager.cs b/src/Identity/Core/src/SignInManager.cs index 0717a8af4b..f523b3319b 100644 --- a/src/Identity/Core/src/SignInManager.cs +++ b/src/Identity/Core/src/SignInManager.cs @@ -378,8 +378,8 @@ namespace Microsoft.AspNetCore.Identity if (await UserManager.CheckPasswordAsync(user, password)) { 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)) + // Only reset the lockout when not in quirks mode if either TFA is not enabled or the client is remembered for TFA. + if (alwaysLockout || !await IsTfaEnabled(user) || await IsTwoFactorClientRememberedAsync(user)) { await ResetLockout(user); } diff --git a/src/Identity/Identity.slnf b/src/Identity/Identity.slnf index 826d00e240..71dbf6e709 100644 --- a/src/Identity/Identity.slnf +++ b/src/Identity/Identity.slnf @@ -82,7 +82,10 @@ "src\\Security\\Authentication\\OAuth\\src\\Microsoft.AspNetCore.Authentication.OAuth.csproj", "src\\Mvc\\Mvc.NewtonsoftJson\\src\\Microsoft.AspNetCore.Mvc.NewtonsoftJson.csproj", "src\\Features\\JsonPatch\\src\\Microsoft.AspNetCore.JsonPatch.csproj", - "src\\Mvc\\Mvc.Testing\\src\\Microsoft.AspNetCore.Mvc.Testing.csproj" + "src\\Mvc\\Mvc.Testing\\src\\Microsoft.AspNetCore.Mvc.Testing.csproj", + "src\\ObjectPool\\src\\Microsoft.Extensions.ObjectPool.csproj", + "src\\Http\\Metadata\\src\\Microsoft.AspNetCore.Metadata.csproj", + "src\\Localization\\Abstractions\\src\\Microsoft.Extensions.Localization.Abstractions.csproj" ] } } diff --git a/src/Identity/test/Identity.Test/SignInManagerTest.cs b/src/Identity/test/Identity.Test/SignInManagerTest.cs index 05839a3580..c65f9900a5 100644 --- a/src/Identity/test/Identity.Test/SignInManagerTest.cs +++ b/src/Identity/test/Identity.Test/SignInManagerTest.cs @@ -267,9 +267,10 @@ namespace Microsoft.AspNetCore.Identity.Test } [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task CheckPasswordOnlyResetLockoutWhenTfaNotEnabled(bool tfaEnabled) + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, false)] + public async Task CheckPasswordOnlyResetLockoutWhenTfaNotEnabledOrRemembered(bool tfaEnabled, bool tfaRemembered) { // Setup var user = new PocoUser { UserName = "Foo" }; @@ -279,20 +280,30 @@ namespace Microsoft.AspNetCore.Identity.Test manager.Setup(m => m.SupportsUserTwoFactor).Returns(tfaEnabled).Verifiable(); manager.Setup(m => m.CheckPasswordAsync(user, "password")).ReturnsAsync(true).Verifiable(); + var context = new DefaultHttpContext(); + var auth = MockAuth(context); + if (tfaEnabled) { manager.Setup(m => m.GetTwoFactorEnabledAsync(user)).ReturnsAsync(true).Verifiable(); manager.Setup(m => m.GetValidTwoFactorProvidersAsync(user)).ReturnsAsync(new string[1] {"Fake"}).Verifiable(); } - else + + if (tfaRemembered) + { + var id = new ClaimsIdentity(IdentityConstants.TwoFactorRememberMeScheme); + id.AddClaim(new Claim(ClaimTypes.Name, user.Id)); + auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorRememberMeScheme)) + .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(id), null, IdentityConstants.TwoFactorRememberMeScheme))).Verifiable(); + } + + if (!tfaEnabled || tfaRemembered) { manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable(); } - var context = new DefaultHttpContext(); - var helper = SetupSignInManager(manager.Object, context); - // Act + var helper = SetupSignInManager(manager.Object, context); var result = await helper.CheckPasswordSignInAsync(user, "password", false); // Assert