Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/skoruba/auditlogging

🕊️ Simple audit logging for .NET Core with EntityFramework Core
https://github.com/skoruba/auditlogging

aspnetcore audit audit-log audit-trail entityframeworkcore identityserver4 logger logging netcore

Last synced: 6 days ago
JSON representation

🕊️ Simple audit logging for .NET Core with EntityFramework Core

Awesome Lists containing this project

README

        

![Logo](docs/Images/Skoruba-ReadMe.png)

# 🕊️ Skoruba.AuditLogging
> Simple audit logging for .NET Core with EntityFramework Core support

**This project is ported to .NET 8.** 🚀

# How to install

```ps
dotnet add package Skoruba.AuditLogging.EntityFramework --version 2.0.0
```

# How to use it

## Setup for web application and auditing of users:

```csharp
services.AddAuditLogging(options =>
{
options.Enabled = true;
options.UseDefaultSubject = true;
options.UseDefaultAction = true;
})
.AddDefaultHttpEventData(subjectOptions =>
{
subjectOptions.SubjectIdentifierClaim = ClaimsConsts.Sub;
subjectOptions.SubjectNameClaim = ClaimsConsts.Name;
},
actionOptions =>
{
actionOptions.IncludeFormVariables = true;
})
.AddDefaultStore(options => options.UseSqlServer(Configuration.GetConnectionString("ApplicationDbContext"),
optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly)))
.AddDefaultAuditSink();
```

## Setup for machine application (e.g. background jobs):
```csharp
services.AddAuditLogging(options =>
{
options.UseDefaultAction = false;
options.Source = "Web"
})
.AddStaticEventSubject(subject =>
{
subject.SubjectType = AuditSubjectTypes.Machine;
subject.SubjectIdentifier = EmailServiceConsts.Name;
subject.SubjectName = Environment.MachineName;
})
.AddDefaultEventAction()
.AddStore>(options =>
options.UseSqlServer(configuration.GetConnectionString("ApplicationDbConnection"),
optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly)))
.AddDefaultAuditSink();
```

## Usage in code

```csharp
// Create fake product
var productDto = new ProductDto
{
Id = Guid.NewGuid().ToString(),
Name = Guid.NewGuid().ToString(),
Category = Guid.NewGuid().ToString()
};

// Log this action
var productGetUserEvent = new ProductGetEvent
{
Product = productDto
};
```

### Logging for user action
```csharp
await _auditEventLogger.LogEventAsync(productGetUserEvent);
```

### Logging for machine action
```csharp
var productGetMachineEvent = new ProductGetEvent
{
Product = productDto,
SubjectType = AuditSubjectTypes.Machine,
SubjectName = Environment.MachineName,
SubjectIdentifier = Environment.MachineName,
Action = new { Method = nameof(Get), Class = nameof(AuditController) }
};

await _auditEventLogger.LogEventAsync(productGetMachineEvent, options =>
{
options.UseDefaultSubject = false;
options.UseDefaultAction = false;
});
```

**ProductAddedEvent.cs**
```csharp
public class ProductAddedEvent : AuditEvent
{
public ProductDto ProductDto { get; set; }
}
```

## AuditEvent - base event for logger

| Property | Description |
|-----------------------|---------------------------------------------------------|
| Event | Name of event |
| Source | Source of logging events |
| Category | Event category |
| SubjectIdentifier | Identifier of caller which is responsible for the event |
| SubjectName | Name of caller which is responsible for the event |
| SubjectType | Subject Type (eg. User/Machine) |
| SubjectAdditionalData | Additional information for subject |
| Action | Information about request/action |

## AuditLog - database table

| Property | Description |
|-----------------------|---------------------------------------------------------|
| Id | Database unique identifier for event |
| Event | Name of event |
| Source | Source of logging events |
| Category | Event category |
| SubjectIdentifier | Identifier of caller which is responsible for the event |
| SubjectName | Name of caller which is responsible for the event |
| SubjectType | Subject Type (eg. User/Machine) |
| SubjectAdditionalData | Additional information for subject |
| Action | Information about request/action |
| Data | Data which are serialized into JSON format |
| Created | Date and time for creating of the event |

## Setup default IAuditSubject and IAuditAction

## `IAuditSubject`
**Default subject implementation for HTTP calls:**

```csharp
public class AuditHttpSubject : IAuditSubject
{
public AuditHttpSubject(IHttpContextAccessor accessor, AuditHttpSubjectOptions options)
{
SubjectIdentifier = accessor.HttpContext.User.FindFirst(options.SubjectIdentifierClaim)?.Value;
SubjectName = accessor.HttpContext.User.FindFirst(options.SubjectNameClaim)?.Value;
SubjectAdditionalData = new
{
RemoteIpAddress = accessor.HttpContext.Connection?.RemoteIpAddress?.ToString(),
LocalIpAddress = accessor.HttpContext.Connection?.LocalIpAddress?.ToString(),
Claims = accessor.HttpContext.User.Claims?.Select(x=> new { x.Type, x.Value })
};
}

public string SubjectName { get; set; }

public string SubjectType { get; set; } = AuditSubjectTypes.User;

public object SubjectAdditionalData { get; set; }

public string SubjectIdentifier { get; set; }
}
```

## `IAuditAction`
**Default action implementation for HTTP calls:**
```csharp
public class AuditHttpAction : IAuditAction
{
public AuditHttpAction(IHttpContextAccessor accessor, AuditHttpActionOptions options)
{
Action = new
{
TraceIdentifier = accessor.HttpContext.TraceIdentifier,
RequestUrl = accessor.HttpContext.Request.GetDisplayUrl(),
HttpMethod = accessor.HttpContext.Request.Method,
FormVariables = options.IncludeFormVariables ? HttpContextHelpers.GetFormVariables(accessor.HttpContext) : null
};
}

public object Action { get; set; }
}
```

## Sinks

### Database migrations

```ps
dotnet ef migrations add DbInit -c DefaultAuditLoggingDbContext -o Data/Migrations
dotnet ef database update -c DefaultAuditLoggingDbContext
```

### Database sink via EntityFramework Core - `DatabaseAuditEventLoggerSink`

- By default it is used database sink via EntityFramework Core, for registration this default sink - it is required to register this method:

```csharp
.AddDefaultStore(options => options.UseSqlServer(Configuration.GetConnectionString("ApplicationDbContext"),
optionsSql => optionsSql.MigrationsAssembly(migrationsAssembly)))
.AddDefaultAuditSink()
```

### AddDefaultStore:

- This method register default implementation of:

- `DefaultAuditLoggingDbContext` - Default DbContext for access to database
- `AuditLog` - Entity for logging all audit stuff
- `AuditLoggingRepository` - Repository for access to database, which contains GRUD method for access to `AuditLog` table.

- In the background it is used method called: `AddStore` - which is possible to use instead of AddDefaultStore and specify individual implementation of these objects above
```csharp
builder.AddStore>(dbContextOptions);
```

### AddDefaultAuditSink:

- This method is for registration of default Sink:

```csharp
builder.AddAuditSinks>();
```

# How to use own Sink

- It is necessary to implement interface `IAuditEventLoggerSink` and one single method called:

```csharp
Task PersistAsync(AuditEvent auditEvent);
```

- Then you can register your new sink via method - `.AddAuditSinks<>` - which has overload for maximum 8 sinks.

# Example

## Source code
- Please, check out the project `Skoruba.AuditLogging.Host` - which contains example with Asp.Net Core API - with fake authentication for testing purpose only. 😊

## Output in JSON format

```json
{
"Id":1,
"Event":"ProductGetEvent",
"Category":"Web",
"SubjectIdentifier":"30256997-4096-428d-bfc7-8593d263b8eb",
"SubjectName":"bob",
"SubjectType":"User",
"SubjectAdditionalData":{
"RemoteIpAddress":"::1",
"LocalIpAddress":"::1",
"Claims":[
{
"Type":"name",
"Value":"bob"
},
{
"Type":"sub",
"Value":"30256997-4096-428d-bfc7-8593d263b8eb"
},
{
"Type":"role",
"Value":"31fad6ad-9df3-4e7f-b73f-68dc7d2636c6"
}
]
},
"Action":{
"TraceIdentifier":"80000025-0000-ff00-b63f-84710c7967bb",
"RequestUrl":"https://localhost:44319/api/audit",
"HttpMethod":"GET"
},
"Data":{
"Product":{
"Id":"7d7138b6-e5c3-4548-814c-9119ddb1f785",
"Name":"c9bc91fe-79f2-439b-8bfa-be3f71947b63",
"Category":"b3f2f9d2-67d5-4b52-8156-04232adf0c4b"
}
},
"Created":"2019-09-09T12:03:12.7729634"
}
```

# Licence
This repository is licensed under the terms of the MIT license.

**NOTE:** This repository uses the source code from https://github.com/IdentityServer/IdentityServer4 which is under the terms of the **[Apache License 2.0](https://github.com/IdentityServer/IdentityServer4/blob/master/LICENSE)**.

# Acknowledgements

- This library is inspired by [EventService from IdentityServer4](https://github.com/IdentityServer/IdentityServer4).