From 1ba0cdbb6926eda2b13b92ff1c5a2f4d3038c648 Mon Sep 17 00:00:00 2001 From: Doug Waldron <737326+dougwaldron@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:47:11 -0500 Subject: [PATCH] Avoid logging email, even masked Fix code scanning alert: Exposure of private information Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../Pages/Account/ExternalLogin.cshtml.cs | 34 +++++++++---------- src/WebApp/Platform/Logging/Redaction.cs | 20 ----------- 2 files changed, 16 insertions(+), 38 deletions(-) delete mode 100644 src/WebApp/Platform/Logging/Redaction.cs diff --git a/src/WebApp/Pages/Account/ExternalLogin.cshtml.cs b/src/WebApp/Pages/Account/ExternalLogin.cshtml.cs index 78105cb..4095eb1 100644 --- a/src/WebApp/Pages/Account/ExternalLogin.cshtml.cs +++ b/src/WebApp/Pages/Account/ExternalLogin.cshtml.cs @@ -8,7 +8,6 @@ using MyApp.AppServices.Staff.Dto; using MyApp.Domain.Identity; using MyApp.WebApp.Models; -using MyApp.WebApp.Platform.Logging; using MyApp.WebApp.Platform.PageModelHelpers; using MyApp.WebApp.Platform.Settings; @@ -94,19 +93,19 @@ public async Task OnGetCallbackAsync(string? returnUrl = null, st if (!userEmail.IsValidEmailDomain()) { - logger.LogWarning("User {UserName} with invalid email domain attempted signin", userEmail.MaskEmail()); + logger.LogWarning("User with invalid email domain {Domain} attempted signin", userEmail.Split('@')[1]); return RedirectToPage("./Unavailable"); } - logger.LogInformation("User {UserName} in tenant {TenantID} successfully authenticated", userEmail.MaskEmail(), - userTenant); + logger.LogInformation("User with object ID {ObjectId} in tenant {TenantID} successfully authenticated", + externalLoginInfo.Principal.GetObjectId(), userTenant); // Determine if a user account already exists with the Object ID. // If not, then determine if a user account already exists with the given username. var user = AppSettings.DevSettings.UseInMemoryData ? await userManager.FindByNameAsync(userEmail) - : await userManager.Users.SingleOrDefaultAsync(u => - u.ObjectIdentifier == externalLoginInfo.Principal.GetObjectId()) ?? + : await userManager.Users.SingleOrDefaultAsync(au => + au.ObjectIdentifier == externalLoginInfo.Principal.GetObjectId()) ?? await userManager.FindByNameAsync(userEmail); // If the user does not have a local account yet, then create one and sign in. @@ -116,7 +115,7 @@ public async Task OnGetCallbackAsync(string? returnUrl = null, st // If user has been marked as inactive, don't sign in. if (!user.Active) { - logger.LogWarning("Inactive user {Email} attempted signin", userEmail.MaskEmail()); + logger.LogWarning("Inactive user with object ID {ObjectId} attempted signin", user.ObjectIdentifier); return RedirectToPage("./Unavailable"); } @@ -165,25 +164,24 @@ private async Task CreateUserAndSignInAsync(ExternalLoginInfo inf var createUserResult = await userManager.CreateAsync(user); if (!createUserResult.Succeeded) { - logger.LogWarning("Failed to create new user {UserName}", user.Email.MaskEmail()); + logger.LogWarning("Failed to create new user with object ID {ObjectId}", user.ObjectIdentifier); return await FailedLoginAsync(createUserResult, user); } - logger.LogInformation("Created new user {Email} with object ID {ObjectId}", - user.Email.MaskEmail(), user.ObjectIdentifier); + logger.LogInformation("Created new user with object ID {ObjectId}", user.ObjectIdentifier); // Add new user to application Roles if seeded in app settings or local admin user setting is enabled. var seedAdminUsers = configuration.GetSection("SeedAdminUsers").Get(); if (AppSettings.DevSettings.LocalUserIsStaff) { - logger.LogInformation("Seeding staff role for new user {Email}", user.Email.MaskEmail()); + logger.LogInformation("Seeding staff role for new user with object ID {ObjectId}", user.ObjectIdentifier); await userManager.AddToRoleAsync(user, RoleName.Staff); } if (AppSettings.DevSettings.LocalUserIsAdmin || (seedAdminUsers != null && seedAdminUsers.Contains(user.Email, StringComparer.InvariantCultureIgnoreCase))) { - logger.LogInformation("Seeding all roles for new user {Email}", user.Email.MaskEmail()); + logger.LogInformation("Seeding all roles for new user with object ID {ObjectId}", user.ObjectIdentifier); foreach (var role in AppRole.AllRoles) await userManager.AddToRoleAsync(user, role.Key); } @@ -196,8 +194,8 @@ private async Task CreateUserAndSignInAsync(ExternalLoginInfo inf // Update local store with from external provider. private async Task RefreshUserInfoAndSignInAsync(ApplicationUser user, ExternalLoginInfo info) { - logger.LogInformation("Existing user {Email} logged in with {LoginProvider} provider", - user.Email.MaskEmail(), info.LoginProvider); + logger.LogInformation("Existing user with object ID {ObjectId} logged in with {LoginProvider} provider", + user.ObjectIdentifier, info.LoginProvider); var previousValues = new ApplicationUser { @@ -232,8 +230,8 @@ private async Task AddLoginProviderAndSignInAsync( if (!addLoginResult.Succeeded) { - logger.LogWarning("Failed to add login provider {LoginProvider} for user {Email}", - info.LoginProvider, user.Email.MaskEmail()); + logger.LogWarning("Failed to add login provider {LoginProvider} for user with object ID {ObjectId}", + info.LoginProvider, user.ObjectIdentifier); return await FailedLoginAsync(addLoginResult, user); } @@ -241,8 +239,8 @@ private async Task AddLoginProviderAndSignInAsync( user.MostRecentLogin = DateTimeOffset.Now; await userManager.UpdateAsync(user); - logger.LogInformation("Login provider {LoginProvider} added for user {Email} with object ID {ObjectId}", - info.LoginProvider, user.Email.MaskEmail(), user.ObjectIdentifier); + logger.LogInformation("Login provider {LoginProvider} added for user with object ID {ObjectId}", + info.LoginProvider, user.ObjectIdentifier); // Include the access token in the properties. var props = new AuthenticationProperties(); diff --git a/src/WebApp/Platform/Logging/Redaction.cs b/src/WebApp/Platform/Logging/Redaction.cs deleted file mode 100644 index 567e83f..0000000 --- a/src/WebApp/Platform/Logging/Redaction.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Text.RegularExpressions; - -namespace MyApp.WebApp.Platform.Logging; - -public static partial class Redaction -{ - public static string MaskEmail(this string? email) - { - if (string.IsNullOrEmpty(email)) return string.Empty; - - var atIndex = email.IndexOf('@'); - if (atIndex <= 1) return email; - - var maskedEmail = MyRegex().Replace(email[..atIndex], "*"); - return string.Concat(maskedEmail, email.AsSpan(atIndex)); - } - - [GeneratedRegex(".(?=.{2})")] - private static partial Regex MyRegex(); -}