Skip to content

Commit

Permalink
- Audit.MongoClient: New extension to audit MongoClient instances.
Browse files Browse the repository at this point in the history
Generate Audit Logs by adding a Command Event Subscriber into the configuration of the MongoDB Driver (#640, #641)
  • Loading branch information
thepirat000 authored and thepirat000 committed Dec 9, 2023
1 parent a293e25 commit bc755e6
Show file tree
Hide file tree
Showing 44 changed files with 1,457 additions and 205 deletions.
24 changes: 23 additions & 1 deletion Audit.NET.sln
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Audit.AzureStorageTables.Un
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Audit.NET.Serilog", "src\Audit.NET.Serilog\Audit.NET.Serilog.csproj", "{BFB6AB47-0ECC-447E-BD37-3D3B8AA5ACE9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Audit.SqlServer.UnitTest", "test\Audit.SqlServer.UnitTest\Audit.SqlServer.UnitTest.csproj", "{B9F11735-5303-47C6-A8FA-EF9EDAD5FBE8}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Audit.SqlServer.UnitTest", "test\Audit.SqlServer.UnitTest\Audit.SqlServer.UnitTest.csproj", "{B9F11735-5303-47C6-A8FA-EF9EDAD5FBE8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Audit.MongoClient", "src\Audit.MongoClient\Audit.MongoClient.csproj", "{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Audit.MongoClient.UnitTest", "test\Audit.MongoClient.UnitTest\Audit.MongoClient.UnitTest.csproj", "{5B3DADC7-981D-42A0-A155-4C3F26DB1991}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -596,6 +600,22 @@ Global
{B9F11735-5303-47C6-A8FA-EF9EDAD5FBE8}.Release|Any CPU.Build.0 = Release|Any CPU
{B9F11735-5303-47C6-A8FA-EF9EDAD5FBE8}.Release|x64.ActiveCfg = Release|Any CPU
{B9F11735-5303-47C6-A8FA-EF9EDAD5FBE8}.Release|x64.Build.0 = Release|Any CPU
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}.Debug|x64.ActiveCfg = Debug|Any CPU
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}.Debug|x64.Build.0 = Debug|Any CPU
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}.Release|Any CPU.Build.0 = Release|Any CPU
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}.Release|x64.ActiveCfg = Release|Any CPU
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA}.Release|x64.Build.0 = Release|Any CPU
{5B3DADC7-981D-42A0-A155-4C3F26DB1991}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B3DADC7-981D-42A0-A155-4C3F26DB1991}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B3DADC7-981D-42A0-A155-4C3F26DB1991}.Debug|x64.ActiveCfg = Debug|Any CPU
{5B3DADC7-981D-42A0-A155-4C3F26DB1991}.Debug|x64.Build.0 = Debug|Any CPU
{5B3DADC7-981D-42A0-A155-4C3F26DB1991}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B3DADC7-981D-42A0-A155-4C3F26DB1991}.Release|Any CPU.Build.0 = Release|Any CPU
{5B3DADC7-981D-42A0-A155-4C3F26DB1991}.Release|x64.ActiveCfg = Release|Any CPU
{5B3DADC7-981D-42A0-A155-4C3F26DB1991}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -659,6 +679,8 @@ Global
{97F2CC5D-6AE6-40E9-AFAC-D4F513C63330} = {A54B4BB6-3439-432B-AFD9-FE62D6528D42}
{BFB6AB47-0ECC-447E-BD37-3D3B8AA5ACE9} = {E62475E8-0BE1-4464-BBD9-FD06CC546593}
{B9F11735-5303-47C6-A8FA-EF9EDAD5FBE8} = {A54B4BB6-3439-432B-AFD9-FE62D6528D42}
{49E52BFD-5E59-4397-93EB-09DCF16FA9CA} = {E62475E8-0BE1-4464-BBD9-FD06CC546593}
{5B3DADC7-981D-42A0-A155-4C3F26DB1991} = {A54B4BB6-3439-432B-AFD9-FE62D6528D42}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B1989475-43D6-4AA5-9717-6DBF734B0C6E}
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ All notable changes to Audit.NET and its extensions will be documented in this f

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).

## [22.1.0] - 2023-12-09:
- Audit.MongoClient: New extension to audit `MongoClient` instances.
Generate Audit Logs by adding a Command Event Subscriber into the configuration of the MongoDB Driver (#640, #641)

## [22.0.2] - 2023-12-01:
- Audit.NET: Support to include the [Activity](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs) distributed trace information into the Audit Event.
- Audit.NET: Adding `Configuration.Reset()` method to reset the global settings to the default.
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>22.0.2</Version>
<Version>22.1.0</Version>
<PackageReleaseNotes></PackageReleaseNotes>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
</PropertyGroup>
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ With Audit.NET you can generate tracking information about operations being exec
[WebAPI](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.WebApi/README.md),
[WCF](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.WCF/README.md),
[File System](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.FileSystem/README.md),
[SignalR](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.SignalR/README.md)
[SignalR](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.SignalR/README.md),
[MongoClient](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.MongoClient/README.md)
and [HttpClient](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.HttpClient/README.md).

## [NuGet](https://www.nuget.org/packages/Audit.NET/)
Expand Down Expand Up @@ -910,6 +911,7 @@ The following packages are extensions to log interactions with different systems
<img src="https://i.imgur.com/p6knit4.png" alt="icon" width="90" /> | **[Audit.WCF](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.WCF/README.md)** | Generate detailed **server-side** audit logs for **Windows Communication Foundation (WCF)** service calls, by configuring a provided behavior.
<img src="https://i.imgur.com/p6knit4.png" alt="icon" width="90" /> | **[Audit.WCF.Client](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.WCF.Client/README.md)** | Generate detailed **client-side** audit logs for **Windows Communication Foundation (WCF)** service calls, by configuring a provided behavior.
<img src="https://i.imgur.com/9go2b0f.png" alt="icon" width="90"/> | **[Audit.WebApi](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.WebApi/README.md)** | Generate detailed audit logs by decorating **Web API** Methods and Controllers with an action filter attribute, or by using a middleware. Includes support for ASP.NET Core.
<img src="https://i.imgur.com/1nMVLQo.png" alt="icon" width="90"/> | **[Audit.MongoClient](https://github.com/thepirat000/Audit.NET/blob/master/src/Audit.MongoClient/README.md)** | Generate detailed audit logs by adding a [Command Event Subscriber](https://mongodb.github.io/mongo-csharp-driver/2.8/reference/driver_core/events/) into the configuration of the MongoDB Driver.
# Storage providers

Expand Down
4 changes: 2 additions & 2 deletions src/Audit.EntityFramework/DbContextHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public static string GetStateName(EntityState state)
public void SaveScope(IAuditDbContext context, IAuditScope scope, EntityFrameworkEvent @event)
{
UpdateAuditEvent(@event, context);
((AuditEventEntityFramework)scope.Event).EntityFrameworkEvent = @event;
scope.EventAs<AuditEventEntityFramework>().EntityFrameworkEvent = @event;
context.OnScopeSaving(scope);
scope.Save();
context.OnScopeSaved(scope);
Expand All @@ -151,7 +151,7 @@ public void SaveScope(IAuditDbContext context, IAuditScope scope, EntityFramewor
public async Task SaveScopeAsync(IAuditDbContext context, IAuditScope scope, EntityFrameworkEvent @event, CancellationToken cancellationToken = default)
{
UpdateAuditEvent(@event, context);
((AuditEventEntityFramework)scope.Event).EntityFrameworkEvent = @event;
scope.EventAs<AuditEventEntityFramework>().EntityFrameworkEvent = @event;
context.OnScopeSaving(scope);
await scope.SaveAsync(cancellationToken);
context.OnScopeSaved(scope);
Expand Down
2 changes: 1 addition & 1 deletion src/Audit.FileSystem/FileSystemMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ private void ProcessEvent(FileSystemEventArgs e, FileSystemEventType type)
{
fsEvent.Errors = null;
}
(auditScope.Event as AuditEventFileSystem).FileSystemEvent = fsEvent;
auditScope.EventAs<AuditEventFileSystem>().FileSystemEvent = fsEvent;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Audit.HttpClient/AuditHttpClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
{
// Update the response and save
action.Response = await GetResponseAudit(response, cancellationToken);
((AuditEventHttpClient)scope.Event).Action = action;
scope.EventAs<AuditEventHttpClient>().Action = action;
await SaveDispose(scope, cancellationToken);
}
return response;
Expand Down
49 changes: 49 additions & 0 deletions src/Audit.MongoClient/Audit.MongoClient.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Generate detailed Audit Logs for operations executed within MongoDB.</Description>
<Copyright>Copyright 2023</Copyright>
<AssemblyTitle>Audit.MongoClient</AssemblyTitle>
<Authors>Federico Colombo</Authors>
<TargetFrameworks>net472;netstandard2.0;net5.0</TargetFrameworks>
<DefineConstants>$(DefineConstants);STRONG_NAME</DefineConstants>
<NoWarn>$(NoWarn);1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>Audit.MongoClient</AssemblyName>
<PackageId>Audit.MongoClient</PackageId>
<PackageTags>Audit;Trail;Log;MongoDB;Client</PackageTags>
<PackageIcon>icon.png</PackageIcon>
<PackageProjectUrl>https://github.com/thepirat000/Audit.NET</PackageProjectUrl>
<NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">2.0.3</NetStandardImplicitPackageVersion>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/thepirat000/Audit.NET</RepositoryUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<None Include="..\..\LICENSE" Pack="true" PackagePath="LICENSE" />
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.22.0" />
</ItemGroup>

<PropertyGroup Condition=" '$(TargetFramework)' != 'net5.0' ">
<DefineConstants>$(DefineConstants);IS_NK_JSON</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net5.0' ">
<DefineConstants>$(DefineConstants);IS_TEXT_JSON</DefineConstants>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Audit.NET\Audit.NET.csproj" />
</ItemGroup>

<ItemGroup>
<None Include="images\icon.png" Pack="true" PackagePath="\" />
</ItemGroup>
</Project>
15 changes: 15 additions & 0 deletions src/Audit.MongoClient/AuditEventMongoCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Audit.Core;

namespace Audit.MongoClient
{
/// <summary>
/// Represents the output of the audit process for a Mongo command event
/// </summary>
public class AuditEventMongoCommand : AuditEvent
{
/// <summary>
/// Gets or sets the Mongo Command details.
/// </summary>
public MongoCommandEvent Command { get; set; }
}
}
72 changes: 72 additions & 0 deletions src/Audit.MongoClient/ConfigurationApi/AuditMongoConfigurator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using Audit.Core;
using MongoDB.Driver.Core.Events;

namespace Audit.MongoClient.ConfigurationApi
{
public class AuditMongoConfigurator : IAuditMongoConfigurator
{
internal Func<CommandSucceededEvent, bool> _includeReplyPredicate;
internal Func<CommandStartedEvent, bool> _commandFilter;
internal Func<CommandStartedEvent, string> _eventTypePredicate;
internal EventCreationPolicy? _eventCreationPolicy;
internal AuditDataProvider _auditDataProvider;
internal IAuditScopeFactory _auditScopeFactory;

/// <inheritdoc />
public IAuditMongoConfigurator IncludeReply(Func<CommandSucceededEvent, bool> includeReplyPredicate)
{
_includeReplyPredicate = includeReplyPredicate;
return this;
}

/// <inheritdoc />
public IAuditMongoConfigurator IncludeReply(bool include = true)
{
_includeReplyPredicate = _ => include;
return this;
}

/// <inheritdoc />
public IAuditMongoConfigurator EventType(Func<CommandStartedEvent, string> eventTypePredicate)
{
_eventTypePredicate = eventTypePredicate;
return this;
}

/// <inheritdoc />
public IAuditMongoConfigurator EventType(string eventType)
{
_eventTypePredicate = _ => eventType;
return this;
}

/// <inheritdoc />
public IAuditMongoConfigurator CommandFilter(Func<CommandStartedEvent, bool> commandFilter)
{
_commandFilter = commandFilter;
return this;
}

/// <inheritdoc />
public IAuditMongoConfigurator AuditScopeFactory(IAuditScopeFactory auditScopeFactory)
{
_auditScopeFactory = auditScopeFactory;
return this;
}

/// <inheritdoc />
public IAuditMongoConfigurator CreationPolicy(EventCreationPolicy eventCreationPolicy)
{
_eventCreationPolicy = eventCreationPolicy;
return this;
}

/// <inheritdoc />
public IAuditMongoConfigurator AuditDataProvider(AuditDataProvider auditDataProvider)
{
_auditDataProvider = auditDataProvider;
return this;
}
}
}
20 changes: 20 additions & 0 deletions src/Audit.MongoClient/ConfigurationApi/ClusterBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using Audit.MongoClient.ConfigurationApi;
using MongoDB.Driver.Core.Configuration;

namespace Audit.MongoClient
{
public static class ClusterBuilderExtensions
{
/// <summary>
/// Adds an Event Subscriber to the MongoDB ClusterBuilder, using the given audit configuration.
/// </summary>
/// <param name="clusterBuilder">The cluster builder</param>
/// <param name="config">The audit configuration. Null to use the default configuration</param>
public static ClusterBuilder AddAuditSubscriber(this ClusterBuilder clusterBuilder, Action<IAuditMongoConfigurator> config = null)
{
clusterBuilder.Subscribe(new MongoAuditEventSubscriber(config));
return clusterBuilder;
}
}
}
57 changes: 57 additions & 0 deletions src/Audit.MongoClient/ConfigurationApi/IAuditMongoConfigurator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using Audit.Core;
using MongoDB.Driver.Core.Events;

namespace Audit.MongoClient.ConfigurationApi
{
public interface IAuditMongoConfigurator
{
/// <summary>
/// Specifies a predicate to determine whether the audit event should include the server reply. The reply is not included by default.
/// </summary>
/// <param name="includeReplyPredicate">A function of the Command Succeeded Event to determine whether to include the the server reply in the audit event</param>
IAuditMongoConfigurator IncludeReply(Func<CommandSucceededEvent, bool> includeReplyPredicate);

/// <summary>
/// Specifies whether the audit event should include the server reply. The reply is not included by default.
/// </summary>
/// <param name="include">True to include the server reply, false otherwise</param>
IAuditMongoConfigurator IncludeReply(bool include = true);

/// <summary>
/// Specifies a predicate to determine the event type name on the audit output.
/// </summary>
/// <param name="eventTypeNamePredicate">A function of the Command Start Event to determine the event type name. The following placeholders can be used as part of the string:
/// - {command}: replaced with the command name.
/// </param>
IAuditMongoConfigurator EventType(Func<CommandStartedEvent, string> eventTypeNamePredicate);
/// <summary>
/// Specifies the event type name to use in the audit output.
/// </summary>
/// <param name="eventTypeName">The event type name to use. The following placeholders can be used as part of the string:
/// - {command}: replaced with the command name.
/// </param>
IAuditMongoConfigurator EventType(string eventTypeName);

/// <summary>
/// Sets a filter function to determine the events to log as a function of the command. By default all commands are logged.
/// </summary>
IAuditMongoConfigurator CommandFilter(Func<CommandStartedEvent, bool> commandFilter);

/// <summary>
/// Specifies the event creation policy to use for this interception. Default is NULL to use the globally configured creation policy.
/// </summary>
/// <param name="eventCreationPolicy">The creation policy to use</param>
IAuditMongoConfigurator CreationPolicy(EventCreationPolicy eventCreationPolicy);

/// <summary>
/// Specifies the audit data provider to use. Default is NULL to use the globally configured data provider.
/// </summary>
IAuditMongoConfigurator AuditDataProvider(AuditDataProvider auditDataProvider);

/// <summary>
/// Specifies the Audit Scope factory to use. Default is NULL to use the default AuditScopeFactory.
/// </summary>
IAuditMongoConfigurator AuditScopeFactory(IAuditScopeFactory auditScopeFactory);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using Audit.MongoClient.ConfigurationApi;
using MongoDB.Driver;

namespace Audit.MongoClient
{
public static class MongoClientSettingsExtensions
{
/// <summary>
/// Adds an Event Subscriber to the MongoClientSetting's ClusterBuilder, using the given audit configuration.
/// </summary>
/// <param name="clientSettings">The client settings instance</param>
/// <param name="config">The audit configuration. Null to use the default configuration</param>
public static MongoClientSettings AddAuditSubscriber(this MongoClientSettings clientSettings, Action<IAuditMongoConfigurator> config = null)
{

if (clientSettings.ClusterConfigurator == null)
{
clientSettings.ClusterConfigurator = cc => cc.AddAuditSubscriber(config);
}
else
{
throw new ArgumentException("Adding an Audit Subscriber to MongoClientSettings is not possible due to an existing ClusterConfigurator. Instead, utilize the AddAuditSubscriber function provided by the ClusterBuilder.");
}
return clientSettings;
}
}
}
Loading

0 comments on commit bc755e6

Please sign in to comment.