Add AllowAnonymous for resetting password navigation flow (#1744)

Addresses #1736 and aspnet/templating#448
This commit is contained in:
Jass Bagga 2018-04-13 16:46:00 -07:00 committed by GitHub
parent e5d9efbd48
commit ae9aa9ebec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 2 deletions

View File

@ -1,10 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{ {
[AllowAnonymous]
public class ForgotPasswordConfirmation : PageModel public class ForgotPasswordConfirmation : PageModel
{ {
public void OnGet() public void OnGet()

View File

@ -1,10 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{ {
[AllowAnonymous]
public class LockoutModel : PageModel public class LockoutModel : PageModel
{ {
public void OnGet() public void OnGet()

View File

@ -4,11 +4,13 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{ {
[AllowAnonymous]
[IdentityDefaultUI(typeof(ResetPasswordModel<>))] [IdentityDefaultUI(typeof(ResetPasswordModel<>))]
public abstract class ResetPasswordModel : PageModel public abstract class ResetPasswordModel : PageModel
{ {

View File

@ -1,10 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal
{ {
[AllowAnonymous]
public class ResetPasswordConfirmationModel : PageModel public class ResetPasswordConfirmationModel : PageModel
{ {
public void OnGet() public void OnGet()

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Razor"> <Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup> <PropertyGroup>
<Description>ASP.NET Core Identity UI is the default Razor Pages built-in UI for the ASP.NET Core Identity framework.</Description> <Description>ASP.NET Core Identity UI is the default Razor Pages built-in UI for the ASP.NET Core Identity framework.</Description>
@ -16,7 +16,7 @@
<EmbeddedResource Remove="wwwroot/**/LICENSE*" /> <EmbeddedResource Remove="wwwroot/**/LICENSE*" />
<None Remove="wwwroot/**/.bower.json" /> <None Remove="wwwroot/**/.bower.json" />
<None Remove="wwwroot/**/LICENSE*" /> <None Remove="wwwroot/**/LICENSE*" />
<None Include="THIRD-PARTY-NOTICES" Pack="true" /> <None Include="THIRD-PARTY-NOTICES" Pack="true" PackagePath="/"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -48,5 +48,8 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
config.Filters.Add(new AuthorizeFilter(policy)); config.Filters.Add(new AuthorizeFilter(policy));
}) })
.Services; .Services;
public static IServiceCollection SetupMaxFailedAccessAttempts(this IServiceCollection services) =>
services.Configure<IdentityOptions>(o => o.Lockout.MaxFailedAccessAttempts = 0);
} }
} }

View File

@ -228,5 +228,60 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
await UserStories.ResetPasswordAsync(resetPasswordClient, email, userName, newPassword); await UserStories.ResetPasswordAsync(resetPasswordClient, email, userName, newPassword);
await UserStories.LoginExistingUserAsync(newClient, userName, newPassword); await UserStories.LoginExistingUserAsync(newClient, userName, newPassword);
} }
[Fact]
public async Task CanResetPassword_WithGlobalAuthorizeFilter()
{
// Arrange
var emailSender = new ContosoEmailSender();
void ConfigureTestServices(IServiceCollection services) =>
services.SetupGlobalAuthorizeFilter().SetupTestEmailSender(emailSender);
var server = ServerFactory.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices));
var client = server.CreateClient();
var resetPasswordClient = server.CreateClient();
var newClient = server.CreateClient();
var userName = $"{Guid.NewGuid()}@example.com";
var password = $"!Test.Password1$";
var newPassword = $"!New.Password1$";
await UserStories.RegisterNewUserAsync(client, userName, password);
var registrationEmail = Assert.Single(emailSender.SentEmails);
await UserStories.ConfirmEmailAsync(registrationEmail, client);
// Act & Assert
await UserStories.ForgotPasswordAsync(resetPasswordClient, userName);
Assert.Equal(2, emailSender.SentEmails.Count);
var email = emailSender.SentEmails[1];
await UserStories.ResetPasswordAsync(resetPasswordClient, email, userName, newPassword);
await UserStories.LoginExistingUserAsync(newClient, userName, newPassword);
}
[Fact]
public async Task UserLockedOut_AfterMaxFailedAccessAttempts_WithGlobalAuthorizeFilter()
{
// Arrange
var emailSender = new ContosoEmailSender();
void ConfigureTestServices(IServiceCollection services) =>
services.SetupGlobalAuthorizeFilter().SetupMaxFailedAccessAttempts().SetupTestEmailSender(emailSender);
var server = ServerFactory.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices));
var client = server.CreateClient();
var newClient = server.CreateClient();
var userName = $"{Guid.NewGuid()}@example.com";
var password = $"!Test.Password1$";
var wrongPassword = $"!Wrong.Password1$";
await UserStories.RegisterNewUserAsync(client, userName, password);
var registrationEmail = Assert.Single(emailSender.SentEmails);
await UserStories.ConfirmEmailAsync(registrationEmail, client);
// Act & Assert
await UserStories.LockoutExistingUserAsync(newClient, userName, wrongPassword);
}
} }
} }

View File

@ -64,6 +64,18 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
Context.WithAuthenticatedUser()); Context.WithAuthenticatedUser());
} }
public async Task<DefaultUIPage> LockoutUserAsync(string userName, string password)
{
var loginAttempt = await SendLoginForm(userName, password);
var lockedOut = ResponseAssert.IsRedirect(loginAttempt);
Assert.Equal("/Identity/Account/Lockout", lockedOut.ToString());
var lockedOutResponse = await Client.GetAsync(lockedOut);
var lockout = await ResponseAssert.IsHtmlDocumentAsync(lockedOutResponse);
return new DefaultUIPage(Client, lockout, Context);
}
private async Task<HttpResponseMessage> SendLoginForm(string userName, string password) private async Task<HttpResponseMessage> SendLoginForm(string userName, string password)
{ {
return await Client.SendAsync(_loginForm, new Dictionary<string, string>() return await Client.SendAsync(_loginForm, new Dictionary<string, string>()

View File

@ -36,6 +36,15 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
return await login.LoginValidUserAsync(userName, password); return await login.LoginValidUserAsync(userName, password);
} }
internal static async Task<DefaultUIPage> LockoutExistingUserAsync(HttpClient client, string userName, string password)
{
var index = await Index.CreateAsync(client);
var login = await index.ClickLoginLinkAsync();
return await login.LockoutUserAsync(userName, password);
}
internal static async Task<Index> RegisterNewUserWithSocialLoginAsync(HttpClient client, string userName, string email) internal static async Task<Index> RegisterNewUserWithSocialLoginAsync(HttpClient client, string userName, string email)
{ {
var index = await Index.CreateAsync(client, new DefaultUIContext().WithSocialLoginEnabled()); var index = await Index.CreateAsync(client, new DefaultUIContext().WithSocialLoginEnabled());