Skip to content

Commit 160f6ad

Browse files
keegan-carusoKeegan Caruso
andauthored
Introduce maxdepth for reading and writing in JsonSerializerPrimitives (#2284)
* Introduce maxdepth for reading and writing in JsonSerializerPrimitives * fix log message * Add tests for objects with more properties * change method of incrementing depth --------- Co-authored-by: Keegan Caruso <[email protected]>
1 parent db6f21c commit 160f6ad

File tree

3 files changed

+244
-24
lines changed

3 files changed

+244
-24
lines changed

src/Microsoft.IdentityModel.Tokens/Json/JsonSerializerPrimitives.cs

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ namespace Microsoft.IdentityModel.Tokens.Json
1818
{
1919
internal static class JsonSerializerPrimitives
2020
{
21+
// This is not a general purpose JSON serializer. It is specifically
22+
// made for the use in the IdentityModel libraries. As such, we can take a
23+
// lower limit to both our reading and writing max depth.
24+
// This number is the min between System.Text.Jsons default for
25+
// writing and reading max depth.
26+
const int MaxDepth = 64;
27+
2128
/// <summary>
2229
/// Creates a JsonException that provides information on what went wrong
2330
/// </summary>
@@ -119,8 +126,14 @@ public static JsonElement CreateJsonElement(string json)
119126
#endif
120127
}
121128

122-
internal static object CreateObjectFromJsonElement(JsonElement jsonElement)
129+
internal static object CreateObjectFromJsonElement(JsonElement jsonElement, int currentDepth)
123130
{
131+
if (currentDepth >= MaxDepth)
132+
throw new InvalidOperationException(LogHelper.FormatInvariant(
133+
LogMessages.IDX10815,
134+
LogHelper.MarkAsNonPII(currentDepth),
135+
LogHelper.MarkAsNonPII(MaxDepth)));
136+
124137
if (jsonElement.ValueKind == JsonValueKind.String)
125138
{
126139
if (DateTime.TryParse(jsonElement.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTime dateTime))
@@ -159,7 +172,9 @@ internal static object CreateObjectFromJsonElement(JsonElement jsonElement)
159172

160173
int index = 0;
161174
foreach (JsonElement j in jsonElement.EnumerateArray())
162-
items[index++] = CreateObjectFromJsonElement(j);
175+
{
176+
items[index++] = CreateObjectFromJsonElement(j, currentDepth + 1);
177+
}
163178

164179
return items;
165180
}
@@ -169,9 +184,12 @@ internal static object CreateObjectFromJsonElement(JsonElement jsonElement)
169184
foreach (JsonProperty property in jsonElement.EnumerateObject())
170185
numItems++;
171186

187+
int index = 0;
172188
KeyValuePair<string, object>[] kvps = new KeyValuePair<string, object>[numItems];
173189
foreach (JsonProperty property in jsonElement.EnumerateObject())
174-
kvps[numItems++] = new KeyValuePair<string, object>(property.Name, CreateObjectFromJsonElement(property.Value));
190+
{
191+
kvps[index++] = new KeyValuePair<string, object>(property.Name, CreateObjectFromJsonElement(property.Value, currentDepth + 1));
192+
}
175193

176194
return kvps;
177195
}
@@ -181,6 +199,8 @@ internal static object CreateObjectFromJsonElement(JsonElement jsonElement)
181199

182200
public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out T t)
183201
{
202+
int currentDepth = 0;
203+
184204
if (typeof(T) == typeof(string))
185205
{
186206
t = (T)(object)jsonElement.ToString();
@@ -272,7 +292,9 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
272292
{
273293
Dictionary<string, object> dictionary = new();
274294
foreach (JsonProperty property in jsonElement.EnumerateObject())
275-
dictionary[property.Name] = CreateObjectFromJsonElement(property.Value);
295+
{
296+
dictionary[property.Name] = CreateObjectFromJsonElement(property.Value, currentDepth + 1);
297+
}
276298

277299
t = (T)(object)dictionary;
278300
return true;
@@ -332,7 +354,9 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
332354
object[] items = new object[numItems];
333355
numItems = 0;
334356
foreach (JsonElement j in jsonElement.EnumerateArray())
335-
items[numItems++] = CreateObjectFromJsonElement(j);
357+
{
358+
items[numItems++] = CreateObjectFromJsonElement(j, currentDepth + 1);
359+
}
336360

337361
t = (T)(object)items;
338362
return true;
@@ -341,7 +365,9 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
341365
{
342366
List<object> items = new();
343367
foreach (JsonElement j in jsonElement.EnumerateArray())
344-
items.Add(CreateObjectFromJsonElement(j));
368+
{
369+
items.Add(CreateObjectFromJsonElement(j, currentDepth + 1));
370+
}
345371

346372
t = (T)(object)items;
347373
return true;
@@ -350,7 +376,9 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
350376
{
351377
Collection<object> items = new();
352378
foreach (JsonElement j in jsonElement.EnumerateArray())
353-
items.Add(CreateObjectFromJsonElement(j));
379+
{
380+
items.Add(CreateObjectFromJsonElement(j, currentDepth + 1));
381+
}
354382

355383
t = (T)(object)items;
356384
return true;
@@ -772,11 +800,14 @@ public static void WriteObjects(ref Utf8JsonWriter writer, IDictionary<string, o
772800
/// general object serializer.
773801
/// If a user needs to serialize a special value, then serialize the value into a JsonElement.
774802
/// </summary>
775-
/// <param name="writer"></param>
776-
/// <param name="key"></param>
777-
/// <param name="obj"></param>
778803
public static void WriteObject(ref Utf8JsonWriter writer, string key, object obj)
779804
{
805+
if (writer.CurrentDepth >= MaxDepth)
806+
throw new InvalidOperationException(LogHelper.FormatInvariant(
807+
LogMessages.IDX10815,
808+
LogHelper.MarkAsNonPII(writer.CurrentDepth),
809+
LogHelper.MarkAsNonPII(MaxDepth)));
810+
780811
if (obj is null)
781812
{
782813
writer.WriteNull(key);
@@ -843,6 +874,12 @@ public static void WriteObject(ref Utf8JsonWriter writer, string key, object obj
843874
/// <param name="obj"></param>
844875
public static void WriteObjectValue(ref Utf8JsonWriter writer, object obj)
845876
{
877+
if (writer.CurrentDepth >= MaxDepth)
878+
throw new InvalidOperationException(LogHelper.FormatInvariant(
879+
LogMessages.IDX10815,
880+
LogHelper.MarkAsNonPII(writer.CurrentDepth),
881+
LogHelper.MarkAsNonPII(MaxDepth)));
882+
846883
Type objType = obj.GetType();
847884

848885
if (obj is string str)

src/Microsoft.IdentityModel.Tokens/LogMessages.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ internal static class LogMessages
238238
public const string IDX10812 = "IDX10812: Unable to create a {0} from the properties found in the JsonWebKey: '{1}'.";
239239
public const string IDX10813 = "IDX10813: Unable to create a {0} from the properties found in the JsonWebKey: '{1}', Exception '{2}'.";
240240
public const string IDX10814 = "IDX10814: Unable to create a {0} from the properties found in the JsonWebKey: '{1}'. Missing: '{2}'.";
241+
public const string IDX10815 = "IDX10815: Depth of JSON: '{0}' exceeds max depth of '{1}'.";
241242

242243
// Base64UrlEncoding
243244
public const string IDX10820 = "IDX10820: Invalid character found in Base64UrlEncoding. Character: '{0}', Encoding: '{1}'.";

0 commit comments

Comments
 (0)