Skip to content

Fix for external logins disappearing after failed login #7002

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,11 @@ public void OnGet() { }
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
{
protected RegisterModel() { }
public System.Collections.Generic.IList<Microsoft.AspNetCore.Authentication.AuthenticationScheme> ExternalLogins { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
[Microsoft.AspNetCore.Mvc.BindPropertyAttribute]
public Microsoft.AspNetCore.Identity.UI.V3.Pages.Account.Internal.RegisterModel.InputModel Input { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public string ReturnUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public virtual void OnGet(string returnUrl = null) { }
public virtual System.Threading.Tasks.Task OnGetAsync(string returnUrl = null) { throw null; }
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync(string returnUrl = null) { throw null; }
public partial class InputModel
{
Expand Down Expand Up @@ -580,10 +581,11 @@ public void OnGet() { }
public abstract partial class RegisterModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
{
protected RegisterModel() { }
public System.Collections.Generic.IList<Microsoft.AspNetCore.Authentication.AuthenticationScheme> ExternalLogins { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
[Microsoft.AspNetCore.Mvc.BindPropertyAttribute]
public Microsoft.AspNetCore.Identity.UI.V4.Pages.Account.Internal.RegisterModel.InputModel Input { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public string ReturnUrl { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public virtual void OnGet(string returnUrl = null) { }
public virtual System.Threading.Tasks.Task OnGetAsync(string returnUrl = null) { throw null; }
public virtual System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult> OnPostAsync(string returnUrl = null) { throw null; }
public partial class InputModel
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ public override async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");

ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<div class="row">
<div class="col-md-4">
<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
<form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
Expand All @@ -27,9 +27,39 @@
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-default">Register</button>
<button id="registerSubmit" type="submit" class="btn btn-default">Register</button>
</form>
</div>
<div class="col-md-6 col-md-offset-2">
<section>
<h4>Use another service to register.</h4>
<hr />
@{
if ((Model.ExternalLogins?.Count ?? 0) == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in Model.ExternalLogins)
{
<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>
</form>
}
}
</section>
</div>
</div>

@section Scripts {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
// 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.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -36,6 +39,12 @@ public abstract class RegisterModel : PageModel
/// </summary>
public string ReturnUrl { get; set; }

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public IList<AuthenticationScheme> ExternalLogins { get; set; }

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down Expand Up @@ -75,7 +84,7 @@ public class InputModel
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public virtual void OnGet(string returnUrl = null) => throw new NotImplementedException();
public virtual Task OnGetAsync(string returnUrl = null) => throw new NotImplementedException();

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
Expand Down Expand Up @@ -108,14 +117,16 @@ public RegisterModel(
_emailSender = emailSender;
}

public override void OnGet(string returnUrl = null)
public override async Task OnGetAsync(string returnUrl = null)
{
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}

public override async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = CreateUser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ public override async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");

ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<div class="row">
<div class="col-md-4">
<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
<form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
Expand All @@ -27,9 +27,39 @@
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Register</button>
<button id="registerSubmit" type="submit" class="btn btn-primary">Register</button>
</form>
</div>
<div class="col-md-6 col-md-offset-2">
<section>
<h4>Use another service to register.</h4>
<hr />
@{
if ((Model.ExternalLogins?.Count ?? 0) == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in Model.ExternalLogins)
{
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
</section>
</div>
</div>

@section Scripts {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
// 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.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -35,6 +38,12 @@ public abstract class RegisterModel : PageModel
/// </summary>
public string ReturnUrl { get; set; }

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public IList<AuthenticationScheme> ExternalLogins { get; set; }

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down Expand Up @@ -74,7 +83,7 @@ public class InputModel
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public virtual void OnGet(string returnUrl = null) => throw new NotImplementedException();
public virtual Task OnGetAsync(string returnUrl = null) => throw new NotImplementedException();

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
Expand Down Expand Up @@ -107,14 +116,16 @@ public RegisterModel(
_emailSender = emailSender;
}

public override void OnGet(string returnUrl = null)
public override async Task OnGetAsync(string returnUrl = null)
{
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}

public override async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = CreateUser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
// 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.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using IdentitySample.DefaultUI.Data;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -38,6 +41,8 @@ public RegisterModel(

public string ReturnUrl { get; set; }

public IList<AuthenticationScheme> ExternalLogins { get; set; }

public class InputModel
{
[Required]
Expand Down Expand Up @@ -67,14 +72,16 @@ public class InputModel
public int Age { get; set; }
}

public void OnGet(string returnUrl = null)
public async Task OnGetAsync(string returnUrl = null)
{
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = new ApplicationUser {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// 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.

using System;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// 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.

using System.Collections.Generic;
Expand All @@ -12,11 +12,29 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account
public class Register : DefaultUIPage
{
private IHtmlFormElement _registerForm;
private IHtmlFormElement _externalLoginForm;
private readonly IHtmlElement _contosoButton;

public Register(HttpClient client, IHtmlDocument register, DefaultUIContext context)
: base(client, register, context)
{
_registerForm = HtmlAssert.HasForm(register);
_registerForm = HtmlAssert.HasForm("#registerForm", register);
if (context.ContosoLoginEnabled)
{
_externalLoginForm = HtmlAssert.HasForm("#external-account", register);
_contosoButton = HtmlAssert.HasElement("button[value=Contoso]", register);
}
}

public async Task<Contoso.Login> ClickLoginWithContosoLinkAsync()
{
var externalFormResponse = await Client.SendAsync(_externalLoginForm, _contosoButton);
var goToContosoLogin = ResponseAssert.IsRedirect(externalFormResponse);
var contosoLoginResponse = await Client.GetAsync(goToContosoLogin);

var contosoLogin = await ResponseAssert.IsHtmlDocumentAsync(contosoLoginResponse);

return new Contoso.Login(Client, contosoLogin, Context);
}

public async Task<Index> SubmitRegisterFormForValidUserAsync(string userName, string password)
Expand Down
24 changes: 22 additions & 2 deletions src/Identity/test/Identity.FunctionalTests/RegistrationTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// 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.

using System;
Expand Down Expand Up @@ -56,7 +56,7 @@ void ConfigureTestServices(IServiceCollection services) =>
}

[Fact]
public async Task CanRegisterWithASocialLoginProvider()
public async Task CanRegisterWithASocialLoginProviderFromLogin()
{
// Arrange
void ConfigureTestServices(IServiceCollection services) =>
Expand All @@ -75,6 +75,26 @@ void ConfigureTestServices(IServiceCollection services) =>
await UserStories.RegisterNewUserWithSocialLoginAsync(client, userName, email);
}

[Fact]
public async Task CanRegisterWithASocialLoginProviderFromRegister()
{
// Arrange
void ConfigureTestServices(IServiceCollection services) =>
services
.SetupTestThirdPartyLogin();

var client = ServerFactory
.WithWebHostBuilder(whb => whb.ConfigureServices(ConfigureTestServices))
.CreateClient();

var guid = Guid.NewGuid();
var userName = $"{guid}";
var email = $"{guid}@example.com";

// Act & Assert
await UserStories.RegisterNewUserWithSocialLoginAsyncViaRegisterPage(client, userName, email);
}

[Fact]
public async Task CanRegisterWithASocialLoginProvider_WithGlobalAuthorizeFilter()
{
Expand Down
Loading