Skip to content

[release/10.0-preview4] Backport identity template fix. #61795

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

Open
wants to merge 3 commits into
base: release/10.0-preview4
Choose a base branch
from
Open
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 @@ -15,7 +15,6 @@ internal sealed class IdentityRedirectManager(NavigationManager navigationManage
MaxAge = TimeSpan.FromSeconds(5),
};

[DoesNotReturn]
public void RedirectTo(string? uri)
{
uri ??= "";
Expand All @@ -26,21 +25,16 @@ public void RedirectTo(string? uri)
uri = navigationManager.ToBaseRelativePath(uri);
}

// During static rendering, NavigateTo throws a NavigationException which is handled by the framework as a redirect.
// So as long as this is called from a statically rendered Identity component, the InvalidOperationException is never thrown.
navigationManager.NavigateTo(uri);
throw new InvalidOperationException($"{nameof(IdentityRedirectManager)} can only be used during static rendering.");
}

[DoesNotReturn]
public void RedirectTo(string uri, Dictionary<string, object?> queryParameters)
{
var uriWithoutQuery = navigationManager.ToAbsoluteUri(uri).GetLeftPart(UriPartial.Path);
var newUri = navigationManager.GetUriWithQueryParameters(uriWithoutQuery, queryParameters);
RedirectTo(newUri);
}

[DoesNotReturn]
public void RedirectToWithStatus(string uri, string message, HttpContext context)
{
context.Response.Cookies.Append(StatusCookieName, message, StatusCookieBuilder.Build(context));
Expand All @@ -49,10 +43,8 @@ public void RedirectToWithStatus(string uri, string message, HttpContext context

private string CurrentPath => navigationManager.ToAbsoluteUri(navigationManager.Uri).GetLeftPart(UriPartial.Path);

[DoesNotReturn]
public void RedirectToCurrentPage() => RedirectTo(CurrentPath);

[DoesNotReturn]
public void RedirectToCurrentPageWithStatus(string message, HttpContext context)
=> RedirectToWithStatus(CurrentPath, message, context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace BlazorWeb_CSharp.Components.Account;

internal sealed class IdentityUserAccessor(UserManager<ApplicationUser> userManager, IdentityRedirectManager redirectManager)
{
public async Task<ApplicationUser> GetRequiredUserAsync(HttpContext context)
public async Task<ApplicationUser?> GetRequiredUserAsync(HttpContext context)
{
var user = await userManager.GetUserAsync(context.User);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
if (UserId is null || Code is null)
{
RedirectManager.RedirectTo("");
return;
}

var user = await UserManager.FindByIdAsync(UserId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
{
RedirectManager.RedirectToWithStatus(
"Account/Login", "Error: Invalid email change confirmation link.", HttpContext);
return;
}

var user = await UserManager.FindByIdAsync(UserId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
if (externalLoginInfo is null)
{
RedirectManager.RedirectToWithStatus("Account/Login", "Error loading external login information.", HttpContext);
return;
}

// Sign in the user with this external login provider if the user already has a login.
Expand All @@ -121,6 +122,7 @@
else if (result.IsLockedOut)
{
RedirectManager.RedirectTo("Account/Lockout");
return;
}

// If the user does not have an account, then ask the user to create an account.
Expand All @@ -135,6 +137,7 @@
if (externalLoginInfo is null)
{
RedirectManager.RedirectToWithStatus("Account/Login", "Error loading external login information during confirmation.", HttpContext);
return;
}

var emailStore = GetEmailStore();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
{
// Don't reveal that the user does not exist or is not confirmed
RedirectManager.RedirectTo("Account/ForgotPasswordConfirmation");
return;
}

// For more information on how to enable account confirmation and password reset please
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

@code {
private string? message;
private ApplicationUser user = default!;
private ApplicationUser? user;
private bool hasPassword;

[CascadingParameter]
Expand All @@ -53,6 +53,11 @@
protected override async Task OnInitializedAsync()
{
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
if (user is null)
{
return;
}

hasPassword = await UserManager.HasPasswordAsync(user);
if (!hasPassword)
{
Expand All @@ -62,6 +67,11 @@

private async Task OnValidSubmitAsync()
{
if (user is null)
{
throw new InvalidOperationException("User is not loaded; cannot change password.");
}

var changePasswordResult = await UserManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword);
if (!changePasswordResult.Succeeded)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

@code {
private string? message;
private ApplicationUser user = default!;
private ApplicationUser? user;
private bool requirePassword;

[CascadingParameter]
Expand All @@ -53,11 +53,19 @@
{
Input ??= new();
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
requirePassword = await UserManager.HasPasswordAsync(user);
if (user is not null)
{
requirePassword = await UserManager.HasPasswordAsync(user);
}
}

private async Task OnValidSubmitAsync()
{
if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to delete personal data.");
}

if (requirePassword && !await UserManager.CheckPasswordAsync(user, Input.Password))
{
message = "Error: Incorrect password.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
</div>

@code {
private ApplicationUser user = default!;
private ApplicationUser? user;

[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
Expand All @@ -40,14 +40,19 @@
{
user = await UserAccessor.GetRequiredUserAsync(HttpContext);

if (HttpMethods.IsGet(HttpContext.Request.Method) && !await UserManager.GetTwoFactorEnabledAsync(user))
if (user is not null && HttpMethods.IsGet(HttpContext.Request.Method) && !await UserManager.GetTwoFactorEnabledAsync(user))
{
throw new InvalidOperationException("Cannot disable 2FA for user as it's not currently enabled.");
}
}

private async Task OnSubmitAsync()
{
if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to disable 2FA.");
}

var disable2faResult = await UserManager.SetTwoFactorEnabledAsync(user, false);
if (!disable2faResult.Succeeded)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

@code {
private string? message;
private ApplicationUser user = default!;
private ApplicationUser? user;
private string? email;
private bool isEmailConfirmed;

Expand All @@ -68,6 +68,11 @@
protected override async Task OnInitializedAsync()
{
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
if (user is null)
{
return;
}

email = await UserManager.GetEmailAsync(user);
isEmailConfirmed = await UserManager.IsEmailConfirmedAsync(user);

Expand All @@ -82,6 +87,11 @@
return;
}

if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to manage email.");
}

var userId = await UserManager.GetUserIdAsync(user);
var code = await UserManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
Expand All @@ -101,6 +111,11 @@
return;
}

if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to send verification email.");
}

var userId = await UserManager.GetUserIdAsync(user);
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ else
private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";

private string? message;
private ApplicationUser user = default!;
private ApplicationUser? user;
private string? sharedKey;
private string? authenticatorUri;
private IEnumerable<string>? recoveryCodes;
Expand All @@ -84,12 +84,19 @@ else
protected override async Task OnInitializedAsync()
{
user = await UserAccessor.GetRequiredUserAsync(HttpContext);

await LoadSharedKeyAndQrCodeUriAsync(user);
if (user is not null)
{
await LoadSharedKeyAndQrCodeUriAsync(user);
}
}

private async Task OnValidSubmitAsync()
{
if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to configure authenticator app.");
}

// Strip spaces and hyphens
var verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
@code {
public const string LinkLoginCallbackAction = "LinkLoginCallback";

private ApplicationUser user = default!;
private ApplicationUser? user;
private IList<UserLoginInfo>? currentLogins;
private IList<AuthenticationScheme>? otherLogins;
private bool showRemoveButton;
Expand All @@ -86,6 +86,11 @@
protected override async Task OnInitializedAsync()
{
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
if (user is null)
{
return;
}

currentLogins = await UserManager.GetLoginsAsync(user);
otherLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync())
.Where(auth => currentLogins.All(ul => auth.Name != ul.LoginProvider))
Expand All @@ -107,6 +112,11 @@

private async Task OnSubmitAsync()
{
if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to remove external login.");
}

var result = await UserManager.RemoveLoginAsync(user, LoginProvider!, ProviderKey!);
if (!result.Succeeded)
{
Expand All @@ -119,11 +129,17 @@

private async Task OnGetLinkLoginCallbackAsync()
{
if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to add external login.");
}

var userId = await UserManager.GetUserIdAsync(user);
var info = await SignInManager.GetExternalLoginInfoAsync(userId);
if (info is null)
{
RedirectManager.RedirectToCurrentPageWithStatus("Error: Could not load external login info.", HttpContext);
return;
}

var result = await UserManager.AddLoginAsync(user, info);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ else

@code {
private string? message;
private ApplicationUser user = default!;
private ApplicationUser? user;
private IEnumerable<string>? recoveryCodes;

[CascadingParameter]
Expand All @@ -49,6 +49,10 @@ else
protected override async Task OnInitializedAsync()
{
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
if (user is null)
{
return;
}

var isTwoFactorEnabled = await UserManager.GetTwoFactorEnabledAsync(user);
if (!isTwoFactorEnabled)
Expand All @@ -59,6 +63,11 @@ else

private async Task OnSubmitAsync()
{
if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to generate recovery codes.");
}

var userId = await UserManager.GetUserIdAsync(user);
recoveryCodes = await UserManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
message = "You have generated new recovery codes.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</div>

@code {
private ApplicationUser user = default!;
private ApplicationUser? user;
private string? username;
private string? phoneNumber;

Expand All @@ -47,6 +47,11 @@
protected override async Task OnInitializedAsync()
{
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
if (user is null)
{
return;
}

username = await UserManager.GetUserNameAsync(user);
phoneNumber = await UserManager.GetPhoneNumberAsync(user);

Expand All @@ -55,6 +60,11 @@

private async Task OnValidSubmitAsync()
{
if (user is null)
{
throw new InvalidOperationException("User is not loaded; failed to set phone number.");
}

if (Input.PhoneNumber != phoneNumber)
{
var setPhoneResult = await UserManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
private async Task OnSubmitAsync()
{
var user = await UserAccessor.GetRequiredUserAsync(HttpContext);
if (user is null)
{
return;
}

await UserManager.SetTwoFactorEnabledAsync(user, false);
await UserManager.ResetAuthenticatorKeyAsync(user);
var userId = await UserManager.GetUserIdAsync(user);
Expand Down
Loading
Loading