Skip to content

Commit

Permalink
Reintroduce BackOfficeUserManagerAuditer
Browse files Browse the repository at this point in the history
  • Loading branch information
Zeegaan committed Oct 24, 2024
1 parent 73d70ba commit 39385be
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.Security;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Notifications;

namespace Umbraco.Cms.Api.Management.DependencyInjection;

Expand All @@ -9,6 +11,13 @@ internal static class AuditLogBuilderExtensions
internal static IUmbracoBuilder AddAuditLogs(this IUmbracoBuilder builder)
{
builder.Services.AddTransient<IAuditLogPresentationFactory, AuditLogPresentationFactory>();
builder.AddNotificationHandler<UserLoginSuccessNotification, BackOfficeUserManagerAuditer>();
builder.AddNotificationHandler<UserLogoutSuccessNotification, BackOfficeUserManagerAuditer>();
builder.AddNotificationHandler<UserLoginFailedNotification, BackOfficeUserManagerAuditer>();
builder.AddNotificationHandler<UserForgotPasswordRequestedNotification, BackOfficeUserManagerAuditer>();
builder.AddNotificationHandler<UserForgotPasswordChangedNotification, BackOfficeUserManagerAuditer>();
builder.AddNotificationHandler<UserPasswordChangedNotification, BackOfficeUserManagerAuditer>();
builder.AddNotificationHandler<UserPasswordResetNotification, BackOfficeUserManagerAuditer>();

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using System.Globalization;

Check warning on line 1 in src/Umbraco.Cms.Api.Management/Security/BackOfficeUserManagerAuditer.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v14/dev)

❌ New issue: Primitive Obsession

In this module, 56.5% of all function arguments are primitive types, threshold = 30.0%. The functions in this file have too many primitive types (e.g. int, double, float) in their function argument lists. Using many primitive types lead to the code smell Primitive Obsession. Avoid adding more primitive arguments.

Check warning on line 1 in src/Umbraco.Cms.Api.Management/Security/BackOfficeUserManagerAuditer.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v14/dev)

❌ New issue: String Heavy Function Arguments

In this module, 47.8% of all arguments to its 11 functions are strings. The threshold for string arguments is 39.0%. The functions in this file have a high ratio of strings as arguments. Avoid adding more.
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.Security;
using Umbraco.Extensions;

namespace Umbraco.Cms.Api.Management.Security;

/// <summary>
/// Binds to notifications to write audit logs for the <see cref="BackOfficeUserManager" />
/// </summary>
internal sealed class BackOfficeUserManagerAuditer :
INotificationHandler<UserLoginSuccessNotification>,
INotificationHandler<UserLogoutSuccessNotification>,
INotificationHandler<UserLoginFailedNotification>,
INotificationHandler<UserForgotPasswordRequestedNotification>,
INotificationHandler<UserForgotPasswordChangedNotification>,
INotificationHandler<UserPasswordChangedNotification>,
INotificationHandler<UserPasswordResetNotification>
{
private readonly IAuditService _auditService;
private readonly IUserService _userService;

public BackOfficeUserManagerAuditer(IAuditService auditService, IUserService userService)
{
_auditService = auditService;
_userService = userService;
}

public void Handle(UserForgotPasswordChangedNotification notification) =>
WriteAudit(
notification.PerformingUserId,
notification.AffectedUserId,
notification.IpAddress,
"umbraco/user/password/forgot/change",
"password forgot/change");

public void Handle(UserForgotPasswordRequestedNotification notification) =>
WriteAudit(
notification.PerformingUserId,
notification.AffectedUserId,
notification.IpAddress,
"umbraco/user/password/forgot/request",
"password forgot/request");

public void Handle(UserLoginFailedNotification notification) =>
WriteAudit(
notification.PerformingUserId,
"0",
notification.IpAddress,
"umbraco/user/sign-in/failed",
"login failed",
string.Empty);

public void Handle(UserLoginSuccessNotification notification)
=> WriteAudit(
notification.PerformingUserId,
notification.AffectedUserId,
notification.IpAddress,
"umbraco/user/sign-in/login",
"login success");

public void Handle(UserLogoutSuccessNotification notification)
=> WriteAudit(
notification.PerformingUserId,
notification.AffectedUserId,
notification.IpAddress,
"umbraco/user/sign-in/logout",
"logout success");

public void Handle(UserPasswordChangedNotification notification) =>
WriteAudit(
notification.PerformingUserId,
notification.AffectedUserId,
notification.IpAddress,
"umbraco/user/password/change",
"password change");

public void Handle(UserPasswordResetNotification notification) =>
WriteAudit(
notification.PerformingUserId,
notification.AffectedUserId,
notification.IpAddress,
"umbraco/user/password/reset",
"password reset");

private static string FormatEmail(IMembershipUser? user) =>
user is null ? string.Empty : user.Email.IsNullOrWhiteSpace() ? string.Empty : $"<{user.Email}>";

private void WriteAudit(
string performingId,
string? affectedId,
string ipAddress,
string eventType,
string eventDetails,
string? affectedDetails = null)
{
IUser? performingUser = null;
if (int.TryParse(performingId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var asInt))
{
performingUser = _userService.GetUserById(asInt);
}

var performingDetails = performingUser == null
? $"User UNKNOWN:{performingId}"
: $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}";

if (!int.TryParse(performingId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var performingIdAsInt))
{
performingIdAsInt = 0;
}

if (!int.TryParse(affectedId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var affectedIdAsInt))
{
affectedIdAsInt = 0;
}

WriteAudit(performingIdAsInt, performingDetails, affectedIdAsInt, ipAddress, eventType, eventDetails, affectedDetails);
}

Check warning on line 121 in src/Umbraco.Cms.Api.Management/Security/BackOfficeUserManagerAuditer.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v14/dev)

❌ New issue: Excess Number of Function Arguments

WriteAudit has 6 arguments, threshold = 4. This function has too many arguments, indicating a lack of encapsulation. Avoid adding more arguments.

private void WriteAudit(
int performingId,
string performingDetails,
int affectedId,
string ipAddress,
string eventType,
string eventDetails,
string? affectedDetails = null)
{
if (affectedDetails == null)
{
IUser? affectedUser = _userService.GetUserById(affectedId);
affectedDetails = affectedUser == null
? $"User UNKNOWN:{affectedId}"
: $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}";
}

_auditService.Write(
performingId,
performingDetails,
ipAddress,
DateTime.UtcNow,
affectedId,
affectedDetails,
eventType,
eventDetails);
}

Check warning on line 149 in src/Umbraco.Cms.Api.Management/Security/BackOfficeUserManagerAuditer.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v14/dev)

❌ New issue: Excess Number of Function Arguments

WriteAudit has 7 arguments, threshold = 4. This function has too many arguments, indicating a lack of encapsulation. Avoid adding more arguments.
}

0 comments on commit 39385be

Please sign in to comment.