Skip to content

Commit 6a6e6cc

Browse files
Add support for masking structured objects that are or contain collections
1 parent cbef705 commit 6a6e6cc

File tree

4 files changed

+152
-8
lines changed

4 files changed

+152
-8
lines changed

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog for Serilog.Enrichers.Sensitive
22

3+
## 1.5.0
4+
5+
- Add support for collections in destructured objects
6+
- Add support for destructured objects which are collections
7+
38
## 1.4.0
49

510
- Add support for masking destructured objects

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>1.4.0.0</Version>
3+
<Version>1.5.0.0</Version>
44
<Authors>Sander van Vliet, Huibert Jan Nieuwkamer, Scott Toberman</Authors>
55
<Company>Codenizer BV</Company>
66
<Copyright>2022 Sander van Vliet</Copyright>

src/Serilog.Enrichers.Sensitive/SensitiveDataEnricher.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ public SensitiveDataEnricher(
3232

3333
if (string.IsNullOrEmpty(enricherOptions.MaskValue))
3434
{
35-
throw new ArgumentNullException("mask", "The mask must be a non-empty string");
35+
throw new ArgumentNullException(nameof(enricherOptions.MaskValue), "The mask must be a non-empty string");
3636
}
3737

3838
_maskingMode = enricherOptions.Mode;
3939
_maskValue = enricherOptions.MaskValue;
40-
_maskProperties = enricherOptions.MaskProperties ?? new List<string>();
41-
_excludeProperties = enricherOptions.ExcludeProperties ?? new List<string>();
40+
_maskProperties = enricherOptions.MaskProperties;
41+
_excludeProperties = enricherOptions.ExcludeProperties;
4242
_maskingOperators = enricherOptions.MaskingOperators.ToList();
4343

4444
var fields = typeof(LogEvent).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
@@ -121,6 +121,25 @@ public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
121121

122122
return (false, null);
123123
}
124+
case SequenceValue sequenceValue:
125+
var resultElements = new List<LogEventPropertyValue>();
126+
var anyElementMasked = false;
127+
foreach (var element in sequenceValue.Elements)
128+
{
129+
var (wasElementMasked, elementResult) = MaskProperty(new KeyValuePair<string, LogEventPropertyValue>(property.Key, element));
130+
131+
if (wasElementMasked)
132+
{
133+
resultElements.Add(elementResult!);
134+
anyElementMasked = true;
135+
}
136+
else
137+
{
138+
resultElements.Add(element);
139+
}
140+
}
141+
142+
return (anyElementMasked, new SequenceValue(resultElements));
124143
case StructureValue structureValue:
125144
{
126145
var propList = new List<LogEventProperty>();

test/Serilog.Enrichers.Sensitive.Tests.Unit/WhenMaskingDestructuredObject.cs

Lines changed: 124 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
using System.Collections.Generic;
2+
using System.Collections.ObjectModel;
3+
using System.Linq;
4+
using FluentAssertions;
25
using Serilog.Core;
6+
using Serilog.Events;
37
using Serilog.Sinks.InMemory;
48
using Serilog.Sinks.InMemory.Assertions;
59
using Xunit;
@@ -29,9 +33,9 @@ public WhenMaskingDestructuredObject()
2933
public void GivenLogMessageWithDestructuredObjectPropertyThatHasSensitiveData_SensitiveDataIsMasked()
3034
{
3135
var testObject = new TestObject();
32-
36+
3337
_logger.Information("Test message {@TestObject}", testObject);
34-
38+
3539
_sink
3640
.Should()
3741
.HaveMessage("Test message {@TestObject}")
@@ -47,7 +51,7 @@ public void GivenLogMessageWithDestructuredObjectPropertyThatHasSensitiveData_Se
4751
public void GivenLogMessageWithDestructuredObjectPropertyThatHasSensitiveDataInNestedProperty_SensitiveDataIsMasked()
4852
{
4953
var testObject = new TestObject();
50-
54+
5155
_logger.Information("Test message {@TestObject}", testObject);
5256

5357
_sink
@@ -74,7 +78,7 @@ public void GivenLogMessageWithDestructuredObjectPropertyWithoutSensitiveDataInN
7478
TestProperty = "also not sensitive"
7579
}
7680
};
77-
81+
7882
_logger.Information("Test message {@TestObject}", testObject);
7983

8084
_sink
@@ -107,17 +111,133 @@ public void GivenConfigurationToMaskSpecificPropertyAndLoggingADestructuredObjec
107111
.WithProperty("SensitiveProperty")
108112
.WithValue("***MASKED***");
109113
}
114+
115+
[Fact]
116+
public void GivenDestructuredObjectHasListOfNestedObjects()
117+
{
118+
var testObject = new TestObject();
119+
120+
_logger.Information("Test message {@TestObject}", testObject);
121+
122+
var elements = _sink
123+
.Should()
124+
.HaveMessage("Test message {@TestObject}")
125+
.Appearing()
126+
.Once()
127+
.WithProperty("TestObject")
128+
.HavingADestructuredObject()
129+
.WithProperty("NestedList")
130+
.Subject
131+
.As<SequenceValue>()
132+
.Elements;
133+
134+
foreach (var structureValue in elements.OfType<StructureValue>())
135+
{
136+
var testProperty = structureValue.Properties.Single(p => p.Name == "TestProperty");
137+
testProperty.Value.ToString().Should().Be("\"***MASKED***\"");
138+
var sensitiveProperty = structureValue.Properties.Single(p => p.Name == "SensitiveProperty");
139+
sensitiveProperty.Value.ToString().Should().Be("\"***MASKED***\"");
140+
}
141+
}
142+
143+
[Fact]
144+
public void GivenDestructuredObjectHasArrayOfNestedObjects()
145+
{
146+
var testObject = new TestObject();
147+
148+
_logger.Information("Test message {@TestObject}", testObject);
149+
150+
var elements = _sink
151+
.Should()
152+
.HaveMessage("Test message {@TestObject}")
153+
.Appearing()
154+
.Once()
155+
.WithProperty("TestObject")
156+
.HavingADestructuredObject()
157+
.WithProperty("NestedArray")
158+
.Subject
159+
.As<SequenceValue>()
160+
.Elements;
161+
162+
foreach (var structureValue in elements.OfType<StructureValue>())
163+
{
164+
var testProperty = structureValue.Properties.Single(p => p.Name == "TestProperty");
165+
testProperty.Value.ToString().Should().Be("\"***MASKED***\"");
166+
var sensitiveProperty = structureValue.Properties.Single(p => p.Name == "SensitiveProperty");
167+
sensitiveProperty.Value.ToString().Should().Be("\"***MASKED***\"");
168+
}
169+
}
170+
171+
[Fact]
172+
public void GivenDestructuredObjectHasCollectionOfNestedObjects()
173+
{
174+
var testObject = new TestObject();
175+
176+
_logger.Information("Test message {@TestObject}", testObject);
177+
178+
var elements = _sink
179+
.Should()
180+
.HaveMessage("Test message {@TestObject}")
181+
.Appearing()
182+
.Once()
183+
.WithProperty("TestObject")
184+
.HavingADestructuredObject()
185+
.WithProperty("NestedCollection")
186+
.Subject
187+
.As<SequenceValue>()
188+
.Elements;
189+
190+
foreach (var structureValue in elements.OfType<StructureValue>())
191+
{
192+
var testProperty = structureValue.Properties.Single(p => p.Name == "TestProperty");
193+
testProperty.Value.ToString().Should().Be("\"***MASKED***\"");
194+
var sensitiveProperty = structureValue.Properties.Single(p => p.Name == "SensitiveProperty");
195+
sensitiveProperty.Value.ToString().Should().Be("\"***MASKED***\"");
196+
}
197+
}
198+
199+
[Fact]
200+
public void GivenDestructuredObjectIsCollectionOfObjects()
201+
{
202+
var collection = new[] { new TestObject(), new TestObject() };
203+
204+
_logger.Information("Test message {@Collection}", collection);
205+
206+
var elements = _sink
207+
.Should()
208+
.HaveMessage("Test message {@Collection}")
209+
.Appearing()
210+
.Once()
211+
.WithProperty("Collection")
212+
.Subject
213+
.As<SequenceValue>()
214+
.Elements;
215+
216+
foreach (var structureValue in elements.OfType<StructureValue>())
217+
{
218+
var testProperty = structureValue.Properties.Single(p => p.Name == "TestProperty");
219+
testProperty.Value.ToString().Should().Be("\"***MASKED***\"");
220+
var sensitiveProperty = structureValue.Properties.Single(p => p.Name == "SensitiveProperty");
221+
sensitiveProperty.Value.ToString().Should().Be("\"***MASKED***\"");
222+
}
223+
}
110224
}
111225

112226
public class TestObject
113227
{
114228
public string TestProperty { get; set; } = "[email protected]";
115229
public string SensitiveProperty { get; set; } = "Super sensitive data";
116230
public NestedTestObject Nested { get; set; } = new NestedTestObject();
231+
232+
public List<NestedTestObject> NestedList { get; set; } = new() { new NestedTestObject(), new NestedTestObject() };
233+
234+
public NestedTestObject[] NestedArray { get; set; } = { new NestedTestObject(), new NestedTestObject() };
235+
public Collection<NestedTestObject> NestedCollection { get; set; } = new() { new NestedTestObject(), new NestedTestObject() };
117236
}
118237

119238
public class NestedTestObject
120239
{
121240
public string TestProperty { get; set; } = "[email protected]";
241+
public string SensitiveProperty { get; set; } = "Super sensitive data";
122242
}
123243
}

0 commit comments

Comments
 (0)