-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
376966d
commit 7eba85f
Showing
6 changed files
with
190 additions
and
3 deletions.
There are no files selected for viewing
41 changes: 41 additions & 0 deletions
41
src/Serilog.Enrichers.AzureClaims/Enrichers/CustomClaimEnricher.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using Microsoft.AspNetCore.Http; | ||
using System.Security.Claims; | ||
|
||
namespace Serilog.Enrichers.AzureClaims; | ||
|
||
/// <summary> | ||
/// Enriches log events with a custom property from the user's claims. | ||
/// </summary> | ||
internal class CustomClaimEnricher : BaseEnricher | ||
{ | ||
private readonly string _customClaimType; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="CustomClaimEnricher"/> class. | ||
/// </summary> | ||
public CustomClaimEnricher(string claimType, string? customPropertyName = null) : base($"Serilog_{customPropertyName ?? claimType}", customPropertyName ?? claimType) | ||
{ | ||
_customClaimType = claimType; | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="CustomClaimEnricher"/> class with the specified HTTP context accessor. | ||
/// </summary> | ||
/// <param name="contextAccessor">The HTTP context accessor to use for retrieving the user's claims.</param> | ||
/// <param name="claimType">The custom claimType to be used to find the claim</param> | ||
/// <param name="customPropertyName">The custom property name to be used in the enriched logs.</param> | ||
internal CustomClaimEnricher(IHttpContextAccessor contextAccessor, string claimType, string? customPropertyName = null) : base(contextAccessor, $"Serilog_{customPropertyName ?? claimType}", customPropertyName ?? claimType) | ||
{ | ||
_customClaimType = claimType; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the Custom Claim property value from the specified claims principal. | ||
/// </summary> | ||
/// <param name="user">The claims principal representing the user.</param> | ||
/// <returns>The Custom Claim property value, or <c>null</c> if it cannot be found.</returns> | ||
protected override string? GetPropertyValue(ClaimsPrincipal user) | ||
{ | ||
return user.FindFirstValue(_customClaimType); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
tests/Serilog.Enrichers.AzureClaims.Tests/CustomClaimEnricherTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
using Microsoft.AspNetCore.Http; | ||
using NSubstitute; | ||
using Serilog.Enrichers.AzureClaims.Tests.Helpers; | ||
using Serilog.Events; | ||
using System.Security.Claims; | ||
using Xunit; | ||
|
||
namespace Serilog.Enrichers.AzureClaims.Tests | ||
{ | ||
public class CustomClaimEnricherTests | ||
{ | ||
private const string _customClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"; | ||
private const string _customClaimPropertyName = "Email"; | ||
|
||
[Fact] | ||
public void LogEvent_DoesNotContainCustomClaimWhenUserIsNotLoggedIn() | ||
{ | ||
// Arrange | ||
var httpContextAccessorMock = Substitute.For<IHttpContextAccessor>(); | ||
httpContextAccessorMock.HttpContext.Returns(new DefaultHttpContext()); | ||
|
||
var CustomClaimEnricher = new CustomClaimEnricher(httpContextAccessorMock, _customClaimType, _customClaimPropertyName); | ||
|
||
LogEvent evt = null; | ||
var log = new LoggerConfiguration() | ||
.Enrich.With(CustomClaimEnricher) | ||
.WriteTo.Sink(new DelegatingSink(e => evt = e)) | ||
.CreateLogger(); | ||
|
||
// Act | ||
log.Information(@"Email property is not set when the user is not logged in"); | ||
|
||
// Assert | ||
Assert.NotNull(evt); | ||
Assert.False(evt.Properties.ContainsKey("Email")); | ||
} | ||
|
||
[Fact] | ||
public void LogEvent_ContainsUnknownCustomClaimWhenUserIsLoggedInButCustomClaimIsNotFound() | ||
{ | ||
// Arrange | ||
var httpContextAccessorMock = Substitute.For<IHttpContextAccessor>(); | ||
var user = new ClaimsPrincipal(TestClaimsProvider.NotValidClaims().GetClaimsPrincipal()); | ||
|
||
httpContextAccessorMock.HttpContext.Returns(new DefaultHttpContext | ||
{ | ||
User = user | ||
}); | ||
|
||
var CustomClaimEnricher = new CustomClaimEnricher(httpContextAccessorMock, _customClaimType, _customClaimPropertyName); | ||
|
||
LogEvent evt = null; | ||
var log = new LoggerConfiguration() | ||
.Enrich.With(CustomClaimEnricher) | ||
.WriteTo.Sink(new DelegatingSink(e => evt = e)) | ||
.CreateLogger(); | ||
|
||
// Act | ||
log.Information(@"Email property is set to unknown when the user is logged in"); | ||
|
||
// Assert | ||
Assert.NotNull(evt); | ||
Assert.True(evt.Properties.ContainsKey("Email")); | ||
Assert.Equal("unknown", evt.Properties["Email"].LiteralValue().ToString()); | ||
} | ||
|
||
[Fact] | ||
public void LogEvent_ContainCustomClaimWhenUserIsLoggedIn() | ||
{ | ||
// Arrange | ||
var httpContextAccessorMock = Substitute.For<IHttpContextAccessor>(); | ||
var user = new ClaimsPrincipal(TestClaimsProvider.ValidClaims().GetClaimsPrincipal()); | ||
|
||
httpContextAccessorMock.HttpContext.Returns(new DefaultHttpContext | ||
{ | ||
User = user | ||
}); | ||
|
||
var CustomClaimEnricher = new CustomClaimEnricher(httpContextAccessorMock, _customClaimType, _customClaimPropertyName); | ||
|
||
LogEvent evt = null; | ||
var log = new LoggerConfiguration() | ||
.Enrich.With(CustomClaimEnricher) | ||
.WriteTo.Sink(new DelegatingSink(e => evt = e)) | ||
.CreateLogger(); | ||
|
||
// Act | ||
log.Information(@"Email property is set when the user is logged in"); | ||
|
||
// Assert | ||
Assert.NotNull(evt); | ||
Assert.True(evt.Properties.ContainsKey("Email")); | ||
Assert.Equal(TestConstants.EMAIL, evt.Properties["Email"].LiteralValue().ToString()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ public static class TestConstants | |
public static string OID = "0f1eddfd-cec1-4444-88f3-07476b7e69ee"; | ||
public static string UPN = "[email protected]"; | ||
public static string TENANTID = "79ce530d-c819-40ed-9a25-eebabd34edfe"; | ||
public static string EMAIL = "[email protected]"; | ||
#pragma warning restore CA2211 // Non-constant fields should not be visible | ||
} | ||
} |