Make all username checks case insensitive in API (#2122)

This commit is contained in:
Leendert de Borst
2026-06-02 12:25:12 +02:00
committed by Leendert de Borst
parent 966db5d110
commit f9edbb0ce3
4 changed files with 35 additions and 16 deletions

View File

@@ -2,6 +2,7 @@
@using AliasVault.Admin.Main.Pages.Users.View.Components
@using AliasVault.Admin.Main.Models
@using AliasVault.Admin.Services
@using AliasVault.Auth
@using Microsoft.EntityFrameworkCore
@inherits MainBase
@inject StatisticsService StatisticsService
@@ -642,6 +643,9 @@ Do you want to proceed with the restoration?")) {
/// </summary>
private async Task ChangeUsername()
{
// Normalize to lowercase and trim to match how usernames are stored at registration.
NewUsername = UsernameHelper.NormalizeUsername(NewUsername);
if (string.IsNullOrWhiteSpace(NewUsername))
{
UsernameValidationError = "Username cannot be empty.";

View File

@@ -458,7 +458,7 @@ public class AuthController(IAliasServerDbContextFactory dbContextFactory, UserM
var user = new AliasVaultUser
{
UserName = model.Username,
UserName = UsernameHelper.NormalizeUsername(model.Username),
SrpIdentity = srpIdentity,
CreatedAt = timeProvider.UtcNow,
UpdatedAt = timeProvider.UtcNow,
@@ -551,7 +551,7 @@ public class AuthController(IAliasServerDbContextFactory dbContextFactory, UserM
return BadRequest(ApiErrorCodeHelper.CreateErrorResponse(ApiErrorCode.USERNAME_REQUIRED, 400));
}
var normalizedUsername = NormalizeUsername(model.Username);
var normalizedUsername = UsernameHelper.NormalizeUsername(model.Username);
var existingUser = await userManager.FindByNameAsync(normalizedUsername);
if (existingUser != null)
@@ -586,7 +586,7 @@ public class AuthController(IAliasServerDbContextFactory dbContextFactory, UserM
}
// Verify the username matches the current user.
if (user.UserName != model.Username)
if (!string.Equals(user.UserName, model.Username, StringComparison.OrdinalIgnoreCase))
{
return BadRequest(ApiErrorCodeHelper.CreateValidationErrorResponse(ApiErrorCode.USERNAME_MISMATCH, 400));
}
@@ -826,7 +826,7 @@ public class AuthController(IAliasServerDbContextFactory dbContextFactory, UserM
}
// Verify the username matches the current user.
if (user.UserName != model.Username)
if (!string.Equals(user.UserName, model.Username, StringComparison.OrdinalIgnoreCase))
{
return BadRequest(ApiErrorCodeHelper.CreateValidationErrorResponse(ApiErrorCode.USERNAME_MISMATCH, 400));
}
@@ -850,16 +850,6 @@ public class AuthController(IAliasServerDbContextFactory dbContextFactory, UserM
return Ok(ApiErrorCodeHelper.CreateErrorResponse(ApiErrorCode.ACCOUNT_SUCCESSFULLY_DELETED, 200));
}
/// <summary>
/// Normalizes a username by trimming and lowercasing it.
/// </summary>
/// <param name="username">The username to normalize.</param>
/// <returns>The normalized username.</returns>
private static string NormalizeUsername(string username)
{
return username.ToLowerInvariant().Trim();
}
/// <summary>
/// Generate a refresh token for a user. This token is used to request a new access token when the current
/// access token expires. The refresh token is long-lived by design.

View File

@@ -145,7 +145,7 @@ public class VaultController(ILogger<VaultController> logger, IAliasServerDbCont
// If they do not match reject the request. This is important because it's
// possible that a user has logged in with a different username than the one
// that is being used to update the vault (e.g. if working with multiple tabs).
if (user.UserName != model.Username)
if (!string.Equals(user.UserName, model.Username, StringComparison.OrdinalIgnoreCase))
{
return BadRequest(ApiErrorCodeHelper.CreateValidationErrorResponse(ApiErrorCode.USERNAME_MISMATCH, 400));
}
@@ -233,7 +233,7 @@ public class VaultController(ILogger<VaultController> logger, IAliasServerDbCont
// If they do not match reject the request. This is important because it's
// possible that a user has logged in with a different username than the one
// that is being used to update the vault (e.g. if working with multiple tabs).
if (model.Username != user.UserName)
if (!string.Equals(user.UserName, model.Username, StringComparison.OrdinalIgnoreCase))
{
return BadRequest(ApiErrorCodeHelper.CreateValidationErrorResponse(ApiErrorCode.USERNAME_MISMATCH, 400));
}

View File

@@ -0,0 +1,25 @@
//-----------------------------------------------------------------------
// <copyright file="UsernameHelper.cs" company="aliasvault">
// Copyright (c) aliasvault. All rights reserved.
// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
// </copyright>
//-----------------------------------------------------------------------
namespace AliasVault.Auth;
/// <summary>
/// Helper for normalizing usernames consistently across the server.
/// </summary>
public static class UsernameHelper
{
/// <summary>
/// Normalizes a username by lowercasing and trimming it.
/// Used by all code paths that store a username.
/// </summary>
/// <param name="username">The username to normalize.</param>
/// <returns>The normalized username.</returns>
public static string NormalizeUsername(string username)
{
return username.ToLowerInvariant().Trim();
}
}