Skip to content

Commit

Permalink
make /accounts status messages error handling more precise
Browse files Browse the repository at this point in the history
  • Loading branch information
NielsPilgaard committed Mar 31, 2024
1 parent dc3493e commit 8b6d7be
Show file tree
Hide file tree
Showing 20 changed files with 135 additions and 95 deletions.
10 changes: 10 additions & 0 deletions src/web/Jordnaer/Components/Account/IdentityRedirectManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Components;
using System.Diagnostics.CodeAnalysis;
using Jordnaer.Components.Account.Shared;

namespace Jordnaer.Components.Account;

Expand Down Expand Up @@ -47,6 +48,15 @@ public void RedirectToWithStatus(string uri, string message, HttpContext context
RedirectTo(uri);
}

[DoesNotReturn]
public void RedirectToWithStatus(string uri, AlertMessage? message, HttpContext context)
{
context.Response.Cookies.Append(key: StatusCookieName,
value: message?.Message ?? string.Empty,
options: StatusCookieBuilder.Build(context));
RedirectTo(uri);
}

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

[DoesNotReturn]
Expand Down
13 changes: 10 additions & 3 deletions src/web/Jordnaer/Components/Account/Pages/ConfirmEmail.razor
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<StatusMessage Message="@_statusMessage" />

@code {
private string? _statusMessage;
private AlertMessage? _statusMessage;

[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
Expand All @@ -34,13 +34,20 @@
if (user is null)
{
HttpContext.Response.StatusCode = StatusCodes.Status404NotFound;
_statusMessage = $"Fejl ved indlæsning af bruger med ID {UserId}";
_statusMessage = new AlertMessage("Fejl ved indlæsning af bruger med ID {UserId}", true);
}
else
{
var code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code));
var result = await UserManager.ConfirmEmailAsync(user, code);
_statusMessage = result.Succeeded ? "Tak fordi du bekræftede din email." : "Fejl ved bekræftelse af email.";
if (result.Succeeded)
{
_statusMessage = new AlertMessage("Tak fordi du bekræftede din email.");
}
else
{
_statusMessage = new AlertMessage("Fejl ved bekræftelse af email.", true);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<StatusMessage Message="@_message" />

@code {
private string? _message;
private AlertMessage? _message;

[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
Expand All @@ -39,19 +39,19 @@
var user = await UserManager.FindByIdAsync(UserId);
if (user is null)
{
_message = "Kan ikke finde bruger med Id '{userId}'";
_message = new AlertMessage($"Kan ikke finde bruger med Id '{UserId}'", true);
return;
}

var code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code));
var result = await UserManager.ChangeEmailAsync(user, Email, code);
if (!result.Succeeded)
{
_message = "Fejl ved ændring af email.";
_message = new AlertMessage("Fejl ved ændring af email.", true);
return;
}

await SignInManager.RefreshSignInAsync(user);
_message = "Tak fordi du bekræftede din emailændring.";
_message = new AlertMessage("Tak fordi du bekræftede din emailændring.");
}
}
105 changes: 53 additions & 52 deletions src/web/Jordnaer/Components/Account/Pages/ExternalLogin.razor
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,29 @@
<hr />

<div class="alert alert-info">
Du er blevet succesfuldt registreret med <strong>@ProviderDisplayName</strong>.
Vælg venligst din emailadresse til denne hjemmeside nedenfor og klik på "Registrer"-knappen for at fuldføre login-processen.
Du er blevet succesfuldt registreret med <strong>@ProviderDisplayName</strong>.
Vælg venligst din emailadresse til denne hjemmeside nedenfor og klik på "Registrer"-knappen for at fuldføre login-processen.
</div>

<div class="row">
<div class="col-md-4">
<EditForm Model="Input" OnValidSubmit="OnValidSubmitAsync" FormName="confirmation" method="post">
<DataAnnotationsValidator />
<ValidationSummary class="text-danger" role="alert" />
<div class="form-floating mb-3">
<InputText @bind-Value="Input.Email" class="form-control" autocomplete="email" placeholder="Indtast venligst din email." />
<label for="email" class="form-label">Email</label>
<ValidationMessage For="() => Input.Email" />
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Registrer</button>
</EditForm>
</div>
<div class="col-md-4">
<EditForm Model="Input" OnValidSubmit="OnValidSubmitAsync" FormName="confirmation" method="post">
<DataAnnotationsValidator />
<ValidationSummary class="text-danger" role="alert" />
<div class="form-floating mb-3">
<InputText @bind-Value="Input.Email" class="form-control" autocomplete="email" placeholder="Indtast venligst din email." />
<label for="email" class="form-label">Email</label>
<ValidationMessage For="() => Input.Email" />
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Registrer</button>
</EditForm>
</div>
</div>

@code {
public const string LoginCallbackAction = "LoginCallback";

private string? _message;
private AlertMessage? _message;
private ExternalLoginInfo? _externalLoginInfo;

[CascadingParameter]
Expand Down Expand Up @@ -101,23 +101,23 @@
_externalLoginInfo.ProviderKey,
isPersistent: false,
bypassTwoFactor: true);

if (result.Succeeded)
{
var user = await UserManager.FindByLoginAsync(_externalLoginInfo.LoginProvider, _externalLoginInfo.ProviderKey);
if (user is null)
{
RedirectManager.RedirectToWithStatus("Account/Login", "Fejl - Det lykkedes ikke at finde dit login. Prøv venligst igen.", HttpContext);
}

var accessToken = _externalLoginInfo.AuthenticationProperties?.GetTokenValue("access_token");
if (accessToken is not null)
{
await Mediator.Publish(new AccessTokenAcquired(user.Id,
var user = await UserManager.FindByLoginAsync(_externalLoginInfo.LoginProvider, _externalLoginInfo.ProviderKey);
if (user is null)
{
RedirectManager.RedirectToWithStatus("Account/Login", "Fejl - Det lykkedes ikke at finde dit login. Prøv venligst igen.", HttpContext);
}

var accessToken = _externalLoginInfo.AuthenticationProperties?.GetTokenValue("access_token");
if (accessToken is not null)
{
await Mediator.Publish(new AccessTokenAcquired(user.Id,
_externalLoginInfo.ProviderKey,
_externalLoginInfo.LoginProvider,
accessToken));
}
accessToken));
}

Logger.LogInformation(
"{Name} logged in with {LoginProvider} provider.",
Expand All @@ -144,42 +144,43 @@
var emailStore = GetEmailStore();
var user = CreateUser();

await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);

var result = await UserManager.CreateAsync(user);
if (result.Succeeded)
if (!result.Succeeded)
{
result = await UserManager.AddLoginAsync(user, _externalLoginInfo!);
if (result.Succeeded)
{
Logger.LogInformation("User created an account using {Name} provider.", _externalLoginInfo!.LoginProvider);
_message = new AlertMessage(result.Errors.Select(error => error.Description), true);
return;
}

var userProfile = _externalLoginInfo!.Principal.ToUserProfile(user.Id);
Context.UserProfiles.Add(userProfile);
await Context.SaveChangesAsync();
result = await UserManager.AddLoginAsync(user, _externalLoginInfo!);
if (result.Succeeded)
{
Logger.LogInformation("User created an account using {Name} provider.", _externalLoginInfo!.LoginProvider);

var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var userProfile = _externalLoginInfo!.Principal.ToUserProfile(user.Id);
Context.UserProfiles.Add(userProfile);
await Context.SaveChangesAsync();

var callbackUrl = NavigationManager.GetUriWithQueryParameters(
NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri,
new Dictionary<string, object?> { ["userId"] = user.Id, ["code"] = code });
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));

await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl));
var callbackUrl = NavigationManager.GetUriWithQueryParameters(
NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri,
new Dictionary<string, object?> { ["userId"] = user.Id, ["code"] = code });

// If account confirmation is required, we need to show the link if we don't have a real email sender
if (UserManager.Options.SignIn.RequireConfirmedAccount)
{
RedirectManager.RedirectTo("Account/RegisterConfirmation", new() { ["email"] = Input.Email });
}
await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl));

await SignInManager.SignInAsync(user, isPersistent: false, _externalLoginInfo.LoginProvider);
RedirectManager.RedirectTo(ReturnUrl);
// If account confirmation is required, we need to show the link if we don't have a real email sender
if (UserManager.Options.SignIn.RequireConfirmedAccount)
{
RedirectManager.RedirectTo("Account/RegisterConfirmation", new() { ["email"] = Input.Email });
}
}

_message = $"Error: {string.Join(",", result.Errors.Select(error => error.Description))}";
await SignInManager.SignInAsync(user, isPersistent: false, _externalLoginInfo.LoginProvider);
RedirectManager.RedirectTo(ReturnUrl);
}
}

private static ApplicationUser CreateUser()
Expand Down
4 changes: 2 additions & 2 deletions src/web/Jordnaer/Components/Account/Pages/Login.razor
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
</div>

@code {
private string? _errorMessage;
private AlertMessage? _errorMessage;

[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
Expand Down Expand Up @@ -102,7 +102,7 @@
}
else
{
_errorMessage = "Ugyldigt login.";
_errorMessage = new AlertMessage("Ugyldigt login.", true);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/web/Jordnaer/Components/Account/Pages/LoginWith2fa.razor
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@


@code {
private string? _message;
private AlertMessage? _message;
private ApplicationUser _user = default!;

[SupplyParameterFromForm]
Expand Down Expand Up @@ -80,7 +80,7 @@
else
{
Logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", userId);
_message = "Ugyldig autentifikations kode.";
_message = new AlertMessage("Ugyldig autentifikations kode.", true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</div>

@code {
private string? _message;
private AlertMessage? _message;
private ApplicationUser _user = default!;

[SupplyParameterFromForm]
Expand Down Expand Up @@ -67,7 +67,7 @@
else
{
Logger.LogWarning("Invalid recovery code entered for user with ID '{UserId}' ", userId);
_message = "Ugyldig autentifikations kode indtastet.";
_message = new AlertMessage("Ugyldig autentifikations kode indtastet.", true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@


@code {
private string? _message;
private AlertMessage? _message;
private ApplicationUser _user = default!;
private bool _hasPassword;

Expand All @@ -62,7 +62,7 @@
var changePasswordResult = await UserManager.ChangePasswordAsync(_user, Input.OldPassword, Input.NewPassword);
if (!changePasswordResult.Succeeded)
{
_message = $"Error: {string.Join(",", changePasswordResult.Errors.Select(error => error.Description))}";
_message = new AlertMessage(changePasswordResult.Errors.Select(error => error.Description), true);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@


@code {
private string? _message;
private AlertMessage? _message;
private ApplicationUser _user = default!;
private bool _requirePassword;

Expand All @@ -56,7 +56,7 @@
{
if (_requirePassword && !await UserManager.CheckPasswordAsync(_user, Input.Password))
{
_message = "Forkert adgangskode.";
_message = new AlertMessage("Forkert adgangskode.", true);
return;
}

Expand Down
8 changes: 4 additions & 4 deletions src/web/Jordnaer/Components/Account/Pages/Manage/Email.razor
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@


@code {
private string? _message;
private AlertMessage? _message;
private ApplicationUser _user = default!;
private string? _email;
private bool _isEmailConfirmed;
Expand All @@ -75,7 +75,7 @@
{
if (Input.NewEmail is null || Input.NewEmail == _email)
{
_message = "Your email is unchanged.";
_message = new AlertMessage("Din email er uændret.", true);
return;
}

Expand All @@ -88,7 +88,7 @@

await EmailSender.SendConfirmationLinkAsync(_user, Input.NewEmail, HtmlEncoder.Default.Encode(callbackUrl));

_message = "Bekræftelses email er sendt. Tjek venligst din email.";
_message = new AlertMessage("Bekræftelses email er sendt. Tjek venligst din email.");
}

private async Task OnSendEmailVerificationAsync()
Expand All @@ -107,7 +107,7 @@

await EmailSender.SendConfirmationLinkAsync(_user, _email, HtmlEncoder.Default.Encode(callbackUrl));

_message = "Bekræftelses email er sendt. Tjek venligst din email.";
_message = new AlertMessage("Bekræftelses email er sendt. Tjek venligst din email.");
}

private sealed class InputModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ else
@code {
private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";

private string? _message;
private AlertMessage? _message;
private ApplicationUser _user = default!;
private string? _sharedKey;
private string? _authenticatorUri;
Expand Down Expand Up @@ -94,15 +94,15 @@ else

if (!is2FaTokenValid)
{
_message = "Din verifikationskode er ugyldig.";
_message = new AlertMessage("Din verifikationskode er ugyldig.", true);
return;
}

await UserManager.SetTwoFactorEnabledAsync(_user, true);
var userId = await UserManager.GetUserIdAsync(_user);
Logger.LogInformation("User with ID '{UserId}' has enabled 2FA with an authenticator app.", userId);

_message = "Din autentifikations app er blevet godkendt.";
_message = new AlertMessage("Din autentifikations app er blevet godkendt.");

if (await UserManager.CountRecoveryCodesAsync(_user) == 0)
{
Expand Down
Loading

0 comments on commit 8b6d7be

Please sign in to comment.