parent
329eed9e8d
commit
641dfe3b62
|
|
@ -4,7 +4,7 @@
|
|||
namespace Microsoft.AspNetCore.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents all the options you can use to configure the cookies middleware uesd by the identity system.
|
||||
/// Represents all the options you can use to configure the cookies middleware used by the identity system.
|
||||
/// </summary>
|
||||
public class IdentityConstants
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
@Html.Partial("_StatusMessage", Model.StatusMessage)
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="post">
|
||||
<form id="change-password-form" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.OldPassword"></label>
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
|
|||
return Page();
|
||||
}
|
||||
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
await _signInManager.RefreshSignInAsync(user);
|
||||
_logger.LogInformation("User changed their password successfully.");
|
||||
StatusMessage = "Your password has been changed.";
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<td>
|
||||
@if (Model.ShowRemoveButton)
|
||||
{
|
||||
<form asp-page-handler="RemoveLogin" method="post">
|
||||
<form id="remove-login" asp-page-handler="RemoveLogin" method="post">
|
||||
<div>
|
||||
<input asp-for="@login.LoginProvider" name="LoginProvider" type="hidden" />
|
||||
<input asp-for="@login.ProviderKey" name="ProviderKey" type="hidden" />
|
||||
|
|
@ -39,12 +39,12 @@
|
|||
{
|
||||
<h4>Add another service to log in.</h4>
|
||||
<hr />
|
||||
<form asp-page-handler="LinkLogin" method="post" class="form-horizontal">
|
||||
<form id="link-login-form" asp-page-handler="LinkLogin" method="post" class="form-horizontal">
|
||||
<div id="socialLoginList">
|
||||
<p>
|
||||
@foreach (var provider in Model.OtherLogins)
|
||||
{
|
||||
<button type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
|
||||
<button id="link-login-button" type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
|
|||
throw new InvalidOperationException($"Unexpected error occurred removing external login for user with ID '{user.Id}'.");
|
||||
}
|
||||
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
await _signInManager.RefreshSignInAsync(user);
|
||||
StatusMessage = "The external login was removed.";
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<form method="post" class="form-group">
|
||||
<button class="btn btn-danger" type="submit">Reset authenticator key</button>
|
||||
<form id="reset-authenticator-form" method="post" class="form-group">
|
||||
<button id="reset-authenticator-button" class="btn btn-danger" type="submit">Reset authenticator key</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
|
|||
await _userManager.ResetAuthenticatorKeyAsync(user);
|
||||
_logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", user.Id);
|
||||
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
await _signInManager.RefreshSignInAsync(user);
|
||||
StatusMessage = "Your authenticator app key has been reset, you will need to configure your authenticator app using the new key.";
|
||||
|
||||
return RedirectToPage("./EnableAuthenticator");
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
</p>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="post">
|
||||
<form id="set-password-form" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.NewPassword"></label>
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Identity.UI.Pages.Account.Manage.Internal
|
|||
return Page();
|
||||
}
|
||||
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
await _signInManager.RefreshSignInAsync(user);
|
||||
StatusMessage = "Your password has been set.";
|
||||
|
||||
return RedirectToPage();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<li class="@ManageNavPages.ChangePasswordNavClass(ViewContext)"><a id="change-password" asp-page="./ChangePassword">Password</a></li>
|
||||
@if ((bool)ViewData["ManageNav.HasExternalLogins"])
|
||||
{
|
||||
<li id="external-logins" class="@ManageNavPages.ExternalLoginsNavClass(ViewContext)"><a asp-page="./ExternalLogins">External logins</a></li>
|
||||
<li id="external-logins" class="@ManageNavPages.ExternalLoginsNavClass(ViewContext)"><a id="external-login" asp-page="./ExternalLogins">External logins</a></li>
|
||||
}
|
||||
<li class="@ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)"><a id="two-factor" asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
|
||||
<li class="@ManageNavPages.PersonalDataNavClass(ViewContext)"><a id="personal-data" asp-page="./PersonalData">Personal data</a></li>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Identity.DefaultUI.WebSite;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
|
|
@ -25,6 +29,13 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
public static IServiceCollection SetupTestEmailSender(this IServiceCollection services, IEmailSender sender) =>
|
||||
services.AddSingleton(sender);
|
||||
|
||||
public static IServiceCollection SetupGetUserClaimsPrincipal(this IServiceCollection services, Action<ClaimsPrincipal> captureUser, string schemeName) =>
|
||||
services.Configure<CookieAuthenticationOptions>(schemeName, o => o.Events.OnSigningIn = context =>
|
||||
{
|
||||
captureUser(context.Principal);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
public static IServiceCollection SetupEmailRequired(this IServiceCollection services) =>
|
||||
services.Configure<IdentityOptions>(o => o.SignIn.RequireConfirmedEmail = true);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,12 @@
|
|||
// 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.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Identity.DefaultUI.WebSite;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||
|
|
@ -53,6 +57,124 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
await UserStories.ConfirmEmailAsync(email, client);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanChangePassword()
|
||||
{
|
||||
// Arrange
|
||||
var principals = new List<ClaimsPrincipal>();
|
||||
var server = ServerFactory.CreateServer(builder =>
|
||||
builder.ConfigureTestServices(s => s.SetupGetUserClaimsPrincipal(user => principals.Add(user), IdentityConstants.ApplicationScheme)));
|
||||
|
||||
var client = ServerFactory.CreateDefaultClient(server);
|
||||
var newClient = ServerFactory.CreateDefaultClient(server);
|
||||
|
||||
var userName = $"{Guid.NewGuid()}@example.com";
|
||||
var password = "!Test.Password1";
|
||||
|
||||
var index = await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||
|
||||
// Act 1
|
||||
var changedPassword = await UserStories.ChangePasswordAsync(index, "!Test.Password1", "!Test.Password2");
|
||||
|
||||
// Assert 1
|
||||
// RefreshSignIn generates a new security stamp claim
|
||||
AssertClaimsNotEqual(principals[0], principals[1], "AspNet.Identity.SecurityStamp");
|
||||
|
||||
// Act 2
|
||||
await UserStories.LoginExistingUserAsync(newClient, userName, "!Test.Password2");
|
||||
|
||||
// Assert 2
|
||||
// Signing in again with a different client uses the same security stamp claim
|
||||
AssertClaimsEqual(principals[1], principals[2], "AspNet.Identity.SecurityStamp");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanSetPasswordWithExternalLogin()
|
||||
{
|
||||
// Arrange
|
||||
var principals = new List<ClaimsPrincipal>();
|
||||
var server = ServerFactory.CreateServer(builder =>
|
||||
builder.ConfigureTestServices(s => s.SetupTestThirdPartyLogin()
|
||||
.SetupGetUserClaimsPrincipal(user => principals.Add(user), IdentityConstants.ApplicationScheme)));
|
||||
|
||||
var client = ServerFactory.CreateDefaultClient(server);
|
||||
var newClient = ServerFactory.CreateDefaultClient(server);
|
||||
|
||||
var guid = Guid.NewGuid();
|
||||
var userName = $"{guid}";
|
||||
var email = $"{guid}@example.com";
|
||||
|
||||
// Act 1
|
||||
var index = await UserStories.RegisterNewUserWithSocialLoginAsync(client, userName, email);
|
||||
index = await UserStories.LoginWithSocialLoginAsync(newClient, userName);
|
||||
|
||||
// Assert 1
|
||||
Assert.NotNull(principals[1].Identities.Single().Claims.Single(c => c.Type == ClaimTypes.AuthenticationMethod).Value);
|
||||
|
||||
// Act 2
|
||||
await UserStories.SetPasswordAsync(index, "!Test.Password2");
|
||||
|
||||
// Assert 2
|
||||
// RefreshSignIn uses the same AuthenticationMethod claim value
|
||||
AssertClaimsEqual(principals[1], principals[2], ClaimTypes.AuthenticationMethod);
|
||||
|
||||
// Act & Assert 3
|
||||
// Can log in with the password set above
|
||||
await UserStories.LoginExistingUserAsync(ServerFactory.CreateDefaultClient(server), email, "!Test.Password2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanRemoveExternalLogin()
|
||||
{
|
||||
// Arrange
|
||||
var principals = new List<ClaimsPrincipal>();
|
||||
var server = ServerFactory.CreateServer(builder =>
|
||||
builder.ConfigureTestServices(s => s.SetupTestThirdPartyLogin()
|
||||
.SetupGetUserClaimsPrincipal(user => principals.Add(user), IdentityConstants.ApplicationScheme)));
|
||||
|
||||
var client = ServerFactory.CreateDefaultClient(server);
|
||||
|
||||
var guid = Guid.NewGuid();
|
||||
var userName = $"{guid}";
|
||||
var email = $"{guid}@example.com";
|
||||
|
||||
// Act
|
||||
var index = await UserStories.RegisterNewUserAsync(client, email, "!TestPassword1");
|
||||
var linkLogin = await UserStories.LinkExternalLoginAsync(index, email);
|
||||
await UserStories.RemoveExternalLoginAsync(linkLogin, email);
|
||||
|
||||
// RefreshSignIn generates a new security stamp claim
|
||||
AssertClaimsNotEqual(principals[0], principals[1], "AspNet.Identity.SecurityStamp");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanResetAuthenticator()
|
||||
{
|
||||
// Arrange
|
||||
var principals = new List<ClaimsPrincipal>();
|
||||
var server = ServerFactory.CreateServer(builder =>
|
||||
builder.ConfigureTestServices(s => s.SetupTestThirdPartyLogin()
|
||||
.SetupGetUserClaimsPrincipal(user => principals.Add(user), IdentityConstants.ApplicationScheme)));
|
||||
|
||||
var client = ServerFactory.CreateDefaultClient(server);
|
||||
var newClient = ServerFactory.CreateDefaultClient(server);
|
||||
|
||||
var userName = $"{Guid.NewGuid()}@example.com";
|
||||
var password = $"!Test.Password1$";
|
||||
|
||||
// Act
|
||||
var loggedIn = await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||
var showRecoveryCodes = await UserStories.EnableTwoFactorAuthentication(loggedIn);
|
||||
var twoFactorKey = showRecoveryCodes.Context.AuthenticatorKey;
|
||||
|
||||
// Use a new client to simulate a new browser session.
|
||||
var index = await UserStories.LoginExistingUser2FaAsync(newClient, userName, password, twoFactorKey);
|
||||
await UserStories.ResetAuthenticator(index);
|
||||
|
||||
// RefreshSignIn generates a new security stamp claim
|
||||
AssertClaimsNotEqual(principals[1], principals[2], "AspNet.Identity.SecurityStamp");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanDownloadPersonalData()
|
||||
{
|
||||
|
|
@ -89,5 +211,19 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
// Act & Assert
|
||||
await UserStories.DeleteUser(index, password);
|
||||
}
|
||||
|
||||
private void AssertClaimsEqual(ClaimsPrincipal expectedPrincipal, ClaimsPrincipal actualPrincipal, string claimType)
|
||||
{
|
||||
var expectedPrincipalClaim = expectedPrincipal.Identities.Single().Claims.Single(c => c.Type == claimType).Value;
|
||||
var actualPrincipalClaim = actualPrincipal.Identities.Single().Claims.Single(c => c.Type == claimType).Value;
|
||||
Assert.Equal(expectedPrincipalClaim, actualPrincipalClaim);
|
||||
}
|
||||
|
||||
private void AssertClaimsNotEqual(ClaimsPrincipal expectedPrincipal, ClaimsPrincipal actualPrincipal, string claimType)
|
||||
{
|
||||
var expectedPrincipalClaim = expectedPrincipal.Identities.Single().Claims.Single(c => c.Type == claimType).Value;
|
||||
var actualPrincipalClaim = actualPrincipal.Identities.Single().Claims.Single(c => c.Type == claimType).Value;
|
||||
Assert.NotEqual(expectedPrincipalClaim, actualPrincipalClaim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
// 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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class ChangePassword : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _changePasswordForm;
|
||||
|
||||
public ChangePassword(HttpClient client, IHtmlDocument changePassword, DefaultUIContext context)
|
||||
: base(client, changePassword, context)
|
||||
{
|
||||
_changePasswordForm = HtmlAssert.HasForm("#change-password-form", changePassword);
|
||||
}
|
||||
|
||||
public async Task<ChangePassword> ChangePasswordAsync(string oldPassword, string newPassword)
|
||||
{
|
||||
await Client.SendAsync(_changePasswordForm, new Dictionary<string, string>
|
||||
{
|
||||
["Input_OldPassword"] = oldPassword,
|
||||
["Input_NewPassword"] = newPassword,
|
||||
["Input_ConfirmPassword"] = newPassword
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
|
|
@ -14,6 +13,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
private readonly IHtmlAnchorElement _profileLink;
|
||||
private readonly IHtmlAnchorElement _changePasswordLink;
|
||||
private readonly IHtmlAnchorElement _twoFactorLink;
|
||||
private readonly IHtmlAnchorElement _externalLoginLink;
|
||||
private readonly IHtmlAnchorElement _personalDataLink;
|
||||
private readonly IHtmlFormElement _updateProfileForm;
|
||||
private readonly IHtmlElement _confirmEmailButton;
|
||||
|
|
@ -27,6 +27,10 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
_profileLink = HtmlAssert.HasLink("#profile", manage);
|
||||
_changePasswordLink = HtmlAssert.HasLink("#change-password", manage);
|
||||
_twoFactorLink = HtmlAssert.HasLink("#two-factor", manage);
|
||||
if (Context.ContosoLoginEnabled)
|
||||
{
|
||||
_externalLoginLink = HtmlAssert.HasLink("#external-login", manage);
|
||||
}
|
||||
_personalDataLink = HtmlAssert.HasLink("#personal-data", manage);
|
||||
_updateProfileForm = HtmlAssert.HasForm("#profile-form", manage);
|
||||
if (!Context.EmailConfirmed)
|
||||
|
|
@ -43,6 +47,14 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
return new TwoFactorAuthentication(Client, twoFactor, Context);
|
||||
}
|
||||
|
||||
public async Task<TwoFactorAuthentication> ClickTwoFactorEnabledLinkAsync()
|
||||
{
|
||||
var goToTwoFactor = await Client.GetAsync(_twoFactorLink.Href);
|
||||
var twoFactor = await ResponseAssert.IsHtmlDocumentAsync(goToTwoFactor);
|
||||
Context.TwoFactorEnabled = true;
|
||||
return new TwoFactorAuthentication(Client, twoFactor, Context);
|
||||
}
|
||||
|
||||
internal async Task<Index> SendConfirmationEmailAsync()
|
||||
{
|
||||
Assert.False(Context.EmailConfirmed);
|
||||
|
|
@ -55,6 +67,22 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
return new Index(Client, manage, Context);
|
||||
}
|
||||
|
||||
public async Task<ChangePassword> ClickChangePasswordLinkAsync()
|
||||
{
|
||||
var goToChangePassword = await Client.GetAsync(_changePasswordLink.Href);
|
||||
var changePasswordDocument = await ResponseAssert.IsHtmlDocumentAsync(goToChangePassword);
|
||||
return new ChangePassword(Client, changePasswordDocument, Context);
|
||||
}
|
||||
|
||||
public async Task<SetPassword> ClickChangePasswordLinkExternalLoginAsync()
|
||||
{
|
||||
var response = await Client.GetAsync(_changePasswordLink.Href);
|
||||
var goToSetPassword = ResponseAssert.IsRedirect(response);
|
||||
var setPasswordResponse = await Client.GetAsync(goToSetPassword);
|
||||
var setPasswordDocument = await ResponseAssert.IsHtmlDocumentAsync(setPasswordResponse);
|
||||
return new SetPassword(Client, setPasswordDocument, Context);
|
||||
}
|
||||
|
||||
public async Task<PersonalData> ClickPersonalDataLinkAsync()
|
||||
{
|
||||
var goToPersonalData = await Client.GetAsync(_personalDataLink.Href);
|
||||
|
|
@ -62,5 +90,12 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
return new PersonalData(Client, personalData, Context);
|
||||
}
|
||||
|
||||
public async Task<LinkExternalLogin> ClickLinkLoginAsync()
|
||||
{
|
||||
var goToExternalLogin = await Client.GetAsync(_externalLoginLink.Href);
|
||||
var externalLoginDocument = await ResponseAssert.IsHtmlDocumentAsync(goToExternalLogin);
|
||||
|
||||
return new LinkExternalLogin(Client, externalLoginDocument, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
// 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.
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class LinkExternalLogin : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _linkLoginForm;
|
||||
private readonly IHtmlElement _linkLoginButton;
|
||||
|
||||
public LinkExternalLogin(HttpClient client, IHtmlDocument externalLoginsDocument, DefaultUIContext context)
|
||||
: base(client, externalLoginsDocument, context)
|
||||
{
|
||||
_linkLoginForm = HtmlAssert.HasForm("#link-login-form", externalLoginsDocument);
|
||||
_linkLoginButton = HtmlAssert.HasElement("#link-login-button", externalLoginsDocument);
|
||||
}
|
||||
|
||||
public async Task<ManageExternalLogin> LinkExternalLoginAsync(string loginEmail)
|
||||
{
|
||||
// Click on the button to link external login to current user account
|
||||
var linkExternalLogin = await Client.SendAsync(_linkLoginForm, _linkLoginButton);
|
||||
var goToLinkExternalLogin = ResponseAssert.IsRedirect(linkExternalLogin);
|
||||
var externalLoginResponse = await Client.GetAsync(goToLinkExternalLogin);
|
||||
var externalLoginDocument = await ResponseAssert.IsHtmlDocumentAsync(externalLoginResponse);
|
||||
|
||||
// Redirected to manage page for external login with a remove button
|
||||
return new ManageExternalLogin(Client, externalLoginDocument, Context);
|
||||
}
|
||||
|
||||
public RemoveExternalLogin ClickRemoveLoginAsync(IHtmlDocument linkedExternalLoginDocument)
|
||||
{
|
||||
return new RemoveExternalLogin(Client, linkedExternalLoginDocument, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// 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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class ManageExternalLogin : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _externalLoginForm;
|
||||
|
||||
public ManageExternalLogin(HttpClient client, IHtmlDocument externalLoginDocument, DefaultUIContext context)
|
||||
: base(client, externalLoginDocument, context)
|
||||
{
|
||||
_externalLoginForm = HtmlAssert.HasForm("#external-login", externalLoginDocument);
|
||||
}
|
||||
|
||||
public async Task<RemoveExternalLogin> ManageExternalLoginAsync(string loginEmail)
|
||||
{
|
||||
var linkedExternalLogin = await Client.SendAsync(_externalLoginForm, new Dictionary<string, string>
|
||||
{
|
||||
["Input_Login"] = loginEmail
|
||||
});
|
||||
|
||||
var goToLinkedExternalLogin = ResponseAssert.IsRedirect(linkedExternalLogin);
|
||||
var externalLoginResponse = await Client.GetAsync(goToLinkedExternalLogin);
|
||||
var goToManageExternalLogin = ResponseAssert.IsRedirect(externalLoginResponse);
|
||||
var manageExternalLoginResponse = await Client.GetAsync(goToManageExternalLogin);
|
||||
|
||||
var manageExternalLoginDocument = await ResponseAssert.IsHtmlDocumentAsync(manageExternalLoginResponse);
|
||||
return new RemoveExternalLogin(Client, manageExternalLoginDocument, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// 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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class RemoveExternalLogin : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _removeLoginForm;
|
||||
|
||||
public RemoveExternalLogin(HttpClient client, IHtmlDocument externalLogin, DefaultUIContext context)
|
||||
: base(client, externalLogin, context)
|
||||
{
|
||||
_removeLoginForm = HtmlAssert.HasForm("#remove-login", externalLogin);
|
||||
}
|
||||
|
||||
public async Task<RemoveExternalLogin> RemoveLoginAsync(string loginProvider, string providerKey)
|
||||
{
|
||||
await Client.SendAsync(_removeLoginForm, new Dictionary<string, string>
|
||||
{
|
||||
["login_LoginProvider"] = loginProvider,
|
||||
["login_ProviderKey"] = providerKey
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// 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.
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class ResetAuthenticator : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _resetAuthenticatorForm;
|
||||
private readonly IHtmlElement _resetAuthenticatorButton;
|
||||
|
||||
public ResetAuthenticator(
|
||||
HttpClient client,
|
||||
IHtmlDocument resetAuthenticator,
|
||||
DefaultUIContext context)
|
||||
: base(client, resetAuthenticator, context)
|
||||
{
|
||||
Assert.True(Context.UserAuthenticated);
|
||||
_resetAuthenticatorForm = HtmlAssert.HasForm("#reset-authenticator-form", resetAuthenticator);
|
||||
_resetAuthenticatorButton = HtmlAssert.HasElement("#reset-authenticator-button", resetAuthenticator);
|
||||
}
|
||||
|
||||
internal async Task<ResetAuthenticator> ResetAuthenticatorAsync()
|
||||
{
|
||||
await Client.SendAsync(_resetAuthenticatorForm, _resetAuthenticatorButton);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// 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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||
{
|
||||
public class SetPassword : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlFormElement _setPasswordForm;
|
||||
|
||||
public SetPassword(HttpClient client, IHtmlDocument setPassword, DefaultUIContext context)
|
||||
: base(client, setPassword, context)
|
||||
{
|
||||
_setPasswordForm = HtmlAssert.HasForm("#set-password-form", setPassword);
|
||||
}
|
||||
|
||||
public async Task<SetPassword> SetPasswordAsync(string newPassword)
|
||||
{
|
||||
await Client.SendAsync(_setPasswordForm, new Dictionary<string, string>
|
||||
{
|
||||
["Input_NewPassword"] = newPassword,
|
||||
["Input_ConfirmPassword"] = newPassword
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
public class TwoFactorAuthentication : DefaultUIPage
|
||||
{
|
||||
private readonly IHtmlAnchorElement _enableAuthenticatorLink;
|
||||
private readonly IHtmlAnchorElement _resetAuthenticatorLink;
|
||||
|
||||
public TwoFactorAuthentication(HttpClient client, IHtmlDocument twoFactor, DefaultUIContext context)
|
||||
: base(client, twoFactor, context)
|
||||
|
|
@ -19,6 +20,10 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
{
|
||||
_enableAuthenticatorLink = HtmlAssert.HasLink("#enable-authenticator", twoFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
_resetAuthenticatorLink = HtmlAssert.HasLink("#reset-authenticator", twoFactor);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<EnableAuthenticator> ClickEnableAuthenticatorLinkAsync()
|
||||
|
|
@ -30,5 +35,13 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
|||
|
||||
return new EnableAuthenticator(Client, enableAuthenticator, Context);
|
||||
}
|
||||
|
||||
internal async Task<ResetAuthenticator> ClickResetAuthenticatorLinkAsync()
|
||||
{
|
||||
var goToResetAuthenticator = await Client.GetAsync(_resetAuthenticatorLink.Href);
|
||||
var resetAuthenticator = await ResponseAssert.IsHtmlDocumentAsync(goToResetAuthenticator);
|
||||
|
||||
return new ResetAuthenticator(Client, resetAuthenticator, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -70,5 +70,16 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
|
||||
return new Account.Manage.Index(Client, manage, Context);
|
||||
}
|
||||
|
||||
internal async Task<Account.Manage.Index> ClickManageLinkWithExternalLoginAsync()
|
||||
{
|
||||
Assert.True(Context.UserAuthenticated);
|
||||
|
||||
var goToManage = await Client.GetAsync(_manageLink.Href);
|
||||
var manage = await ResponseAssert.IsHtmlDocumentAsync(goToManage);
|
||||
Context.ContosoLoginEnabled = true;
|
||||
|
||||
return new Account.Manage.Index(Client, manage, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,14 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
return await enableAuthenticator.SendValidCodeAsync();
|
||||
}
|
||||
|
||||
internal static async Task<ResetAuthenticator> ResetAuthenticator(Index index)
|
||||
{
|
||||
var manage = await index.ClickManageLinkAsync();
|
||||
var twoFactor = await manage.ClickTwoFactorEnabledLinkAsync();
|
||||
var resetAuthenticator = await twoFactor.ClickResetAuthenticatorLinkAsync();
|
||||
return await resetAuthenticator.ResetAuthenticatorAsync();
|
||||
}
|
||||
|
||||
internal static async Task<Index> LoginExistingUserRecoveryCodeAsync(
|
||||
HttpClient client,
|
||||
string userName,
|
||||
|
|
@ -136,6 +144,39 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
return await resetPassword.SendNewPasswordAsync(email, newPassword);
|
||||
}
|
||||
|
||||
internal static async Task<ChangePassword> ChangePasswordAsync(Index index, string oldPassword, string newPassword)
|
||||
{
|
||||
var manage = await index.ClickManageLinkAsync();
|
||||
var changePassword = await manage.ClickChangePasswordLinkAsync();
|
||||
|
||||
return await changePassword.ChangePasswordAsync(oldPassword, newPassword);
|
||||
}
|
||||
|
||||
internal static async Task<SetPassword> SetPasswordAsync(Index index, string newPassword)
|
||||
{
|
||||
var manage = await index.ClickManageLinkAsync();
|
||||
var setPassword = await manage.ClickChangePasswordLinkExternalLoginAsync();
|
||||
|
||||
return await setPassword.SetPasswordAsync(newPassword);
|
||||
}
|
||||
|
||||
internal static async Task<ManageExternalLogin> LinkExternalLoginAsync(Index index, string loginEmail)
|
||||
{
|
||||
var manage = await index.ClickManageLinkWithExternalLoginAsync();
|
||||
var linkLogin = await manage.ClickLinkLoginAsync();
|
||||
|
||||
return await linkLogin.LinkExternalLoginAsync(loginEmail);
|
||||
}
|
||||
|
||||
internal static async Task<RemoveExternalLogin> RemoveExternalLoginAsync(ManageExternalLogin manageExternalLogin, string loginEmail)
|
||||
{
|
||||
// Provide an email to link an external account to
|
||||
var removeLogin = await manageExternalLogin.ManageExternalLoginAsync(loginEmail);
|
||||
|
||||
// Remove external login
|
||||
return await removeLogin.RemoveLoginAsync("Contoso", "Contoso");
|
||||
}
|
||||
|
||||
internal static async Task<Index> DeleteUser(Index index, string password)
|
||||
{
|
||||
var manage = await index.ClickManageLinkAsync();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<section>
|
||||
<form method="post">
|
||||
<form id="external-login" method="post">
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Input.Login"></label>
|
||||
|
|
|
|||
Loading…
Reference in New Issue