From 5212353f4c6ed15b1a0be5ec35221e16eca598d9 Mon Sep 17 00:00:00 2001 From: Rolf Kristensen Date: Sat, 10 Sep 2022 12:48:11 +0200 Subject: [PATCH] MetadataDictionaryConverter - Protect against bad types --- .../Serialization/JsonConfiguration.cs | 24 +++++++++++++-- .../MetadataDictionaryConverter.cs | 21 +++++++++----- .../MessageTests.cs | 29 +++++++++++++++++++ 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs b/src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs index b1353720..c2111424 100644 --- a/src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs +++ b/src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information using System; +using System.Buffers.Text; +using System.Buffers; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; @@ -18,14 +20,32 @@ public static class EcsJsonConfiguration PropertyNamingPolicy = new SnakeCaseJsonNamingPolicy(), Converters = { - new EcsDocumentJsonConverterFactory() + new EcsDocumentJsonConverterFactory(), + new JsonStringConverter(), // Cannot transfer assembly-objects over the wire + new JsonStringConverter(), // Cannot transfer module-objects over the wire + new JsonStringConverter(),// Cannot transfer method-addresses over the wire + new JsonStringConverter(), // Cannot transfer methods over the wire + new JsonStringConverter(), // Cannot transfer types over the wire + new JsonStringConverter(), // Stream-properties often throws exceptions }, - }; internal static readonly JsonConverter DateTimeOffsetConverter = (JsonConverter)SerializerOptions.GetConverter(typeof(DateTimeOffset)); public static readonly EcsDocumentJsonConverter DefaultEcsDocumentJsonConverter = new(); + + public class JsonStringConverter : JsonConverter + { + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => default; + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + if (value is null) + writer.WriteNullValue(); + else + writer.WriteStringValue(value.ToString()); + } + } } } diff --git a/src/Elastic.CommonSchema/Serialization/MetadataDictionaryConverter.cs b/src/Elastic.CommonSchema/Serialization/MetadataDictionaryConverter.cs index 6df8358a..79f29f53 100644 --- a/src/Elastic.CommonSchema/Serialization/MetadataDictionaryConverter.cs +++ b/src/Elastic.CommonSchema/Serialization/MetadataDictionaryConverter.cs @@ -63,17 +63,24 @@ private object ExtractValue(ref Utf8JsonReader reader, JsonSerializerOptions opt { switch (reader.TokenType) { - case JsonTokenType.String when reader.TryGetDateTime(out var date): return date; - case JsonTokenType.String: return reader.GetString(); - case JsonTokenType.False: return false; - case JsonTokenType.True: return true; - case JsonTokenType.Null: return null; - case JsonTokenType.Number: return reader.TryGetInt64(out var result) ? result : reader.TryGetDouble(out var d) ? d : reader.GetDecimal(); + case JsonTokenType.String when reader.TryGetDateTime(out var date): + return date; + case JsonTokenType.String: + return reader.GetString(); + case JsonTokenType.False: + return false; + case JsonTokenType.True: + return true; + case JsonTokenType.Null: + return null; + case JsonTokenType.Number: + return reader.TryGetInt64(out var result) ? result : reader.TryGetDouble(out var d) ? d : reader.GetDecimal(); case JsonTokenType.StartObject: return Read(ref reader, null, options); case JsonTokenType.StartArray: var list = new List(); - while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) list.Add(ExtractValue(ref reader, options)); + while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) + list.Add(ExtractValue(ref reader, options)); return list; case JsonTokenType.None: case JsonTokenType.EndObject: diff --git a/tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs b/tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs index e9755b3e..22524c21 100644 --- a/tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs +++ b/tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs @@ -49,6 +49,35 @@ public void SeesMessageWithProp() => TestLogger((logger, getLogEvents) => y.Should().HaveValue().And.Be(2.2); }); + [Fact] + public void SeesMessageWithEvilProp() => TestLogger((logger, getLogEvents) => + { + logger.Info("Info {EvilValue}", new BadObject()); + + var logEvents = getLogEvents(); + logEvents.Should().HaveCount(1); + + var ecsEvents = ToEcsEvents(logEvents); + + var (_, info) = ecsEvents.First(); + info.Message.Should().Be("Info Elastic.CommonSchema.NLog.Tests.MessageTests+BadObject"); + info.Metadata.Should().ContainKey("EvilValue"); + + var x = info.Metadata["EvilValue"] as System.Collections.Generic.Dictionary; + x.Should().NotBeNull().And.NotBeEmpty(); + }); + + class BadObject + { + // public IEnumerable Recursive => new List(new[] { "Hello", (object)this }) + + // public string EvilProperty => throw new NotSupportedException() + + public System.Type TypeProperty { get; } = typeof(BadObject); + + // public System.Action WeirdProperty { get; } = new System.Action(() => throw new NotSupportedException()); + } + [Fact] public void SeesMessageWithException() => TestLogger((logger, getLogEvents) => {