Skip to content

Commit

Permalink
Introduce maxdepth for reading and writing in JsonSerializerPrimitives (
Browse files Browse the repository at this point in the history
#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]>
  • Loading branch information
keegan-caruso and Keegan Caruso authored Aug 31, 2023
1 parent db6f21c commit 160f6ad
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 24 deletions.
57 changes: 47 additions & 10 deletions src/Microsoft.IdentityModel.Tokens/Json/JsonSerializerPrimitives.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ namespace Microsoft.IdentityModel.Tokens.Json
{
internal static class JsonSerializerPrimitives
{
// This is not a general purpose JSON serializer. It is specifically
// made for the use in the IdentityModel libraries. As such, we can take a
// lower limit to both our reading and writing max depth.
// This number is the min between System.Text.Jsons default for
// writing and reading max depth.
const int MaxDepth = 64;

/// <summary>
/// Creates a JsonException that provides information on what went wrong
/// </summary>
Expand Down Expand Up @@ -119,8 +126,14 @@ public static JsonElement CreateJsonElement(string json)
#endif
}

internal static object CreateObjectFromJsonElement(JsonElement jsonElement)
internal static object CreateObjectFromJsonElement(JsonElement jsonElement, int currentDepth)
{
if (currentDepth >= MaxDepth)
throw new InvalidOperationException(LogHelper.FormatInvariant(
LogMessages.IDX10815,
LogHelper.MarkAsNonPII(currentDepth),
LogHelper.MarkAsNonPII(MaxDepth)));

if (jsonElement.ValueKind == JsonValueKind.String)
{
if (DateTime.TryParse(jsonElement.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTime dateTime))
Expand Down Expand Up @@ -159,7 +172,9 @@ internal static object CreateObjectFromJsonElement(JsonElement jsonElement)

int index = 0;
foreach (JsonElement j in jsonElement.EnumerateArray())
items[index++] = CreateObjectFromJsonElement(j);
{
items[index++] = CreateObjectFromJsonElement(j, currentDepth + 1);
}

return items;
}
Expand All @@ -169,9 +184,12 @@ internal static object CreateObjectFromJsonElement(JsonElement jsonElement)
foreach (JsonProperty property in jsonElement.EnumerateObject())
numItems++;

int index = 0;
KeyValuePair<string, object>[] kvps = new KeyValuePair<string, object>[numItems];
foreach (JsonProperty property in jsonElement.EnumerateObject())
kvps[numItems++] = new KeyValuePair<string, object>(property.Name, CreateObjectFromJsonElement(property.Value));
{
kvps[index++] = new KeyValuePair<string, object>(property.Name, CreateObjectFromJsonElement(property.Value, currentDepth + 1));
}

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

public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out T t)
{
int currentDepth = 0;

if (typeof(T) == typeof(string))
{
t = (T)(object)jsonElement.ToString();
Expand Down Expand Up @@ -272,7 +292,9 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
{
Dictionary<string, object> dictionary = new();
foreach (JsonProperty property in jsonElement.EnumerateObject())
dictionary[property.Name] = CreateObjectFromJsonElement(property.Value);
{
dictionary[property.Name] = CreateObjectFromJsonElement(property.Value, currentDepth + 1);
}

t = (T)(object)dictionary;
return true;
Expand Down Expand Up @@ -332,7 +354,9 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
object[] items = new object[numItems];
numItems = 0;
foreach (JsonElement j in jsonElement.EnumerateArray())
items[numItems++] = CreateObjectFromJsonElement(j);
{
items[numItems++] = CreateObjectFromJsonElement(j, currentDepth + 1);
}

t = (T)(object)items;
return true;
Expand All @@ -341,7 +365,9 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
{
List<object> items = new();
foreach (JsonElement j in jsonElement.EnumerateArray())
items.Add(CreateObjectFromJsonElement(j));
{
items.Add(CreateObjectFromJsonElement(j, currentDepth + 1));
}

t = (T)(object)items;
return true;
Expand All @@ -350,7 +376,9 @@ public static bool TryCreateTypeFromJsonElement<T>(JsonElement jsonElement, out
{
Collection<object> items = new();
foreach (JsonElement j in jsonElement.EnumerateArray())
items.Add(CreateObjectFromJsonElement(j));
{
items.Add(CreateObjectFromJsonElement(j, currentDepth + 1));
}

t = (T)(object)items;
return true;
Expand Down Expand Up @@ -772,11 +800,14 @@ public static void WriteObjects(ref Utf8JsonWriter writer, IDictionary<string, o
/// general object serializer.
/// If a user needs to serialize a special value, then serialize the value into a JsonElement.
/// </summary>
/// <param name="writer"></param>
/// <param name="key"></param>
/// <param name="obj"></param>
public static void WriteObject(ref Utf8JsonWriter writer, string key, object obj)
{
if (writer.CurrentDepth >= MaxDepth)
throw new InvalidOperationException(LogHelper.FormatInvariant(
LogMessages.IDX10815,
LogHelper.MarkAsNonPII(writer.CurrentDepth),
LogHelper.MarkAsNonPII(MaxDepth)));

if (obj is null)
{
writer.WriteNull(key);
Expand Down Expand Up @@ -843,6 +874,12 @@ public static void WriteObject(ref Utf8JsonWriter writer, string key, object obj
/// <param name="obj"></param>
public static void WriteObjectValue(ref Utf8JsonWriter writer, object obj)
{
if (writer.CurrentDepth >= MaxDepth)
throw new InvalidOperationException(LogHelper.FormatInvariant(
LogMessages.IDX10815,
LogHelper.MarkAsNonPII(writer.CurrentDepth),
LogHelper.MarkAsNonPII(MaxDepth)));

Type objType = obj.GetType();

if (obj is string str)
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.IdentityModel.Tokens/LogMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ internal static class LogMessages
public const string IDX10812 = "IDX10812: Unable to create a {0} from the properties found in the JsonWebKey: '{1}'.";
public const string IDX10813 = "IDX10813: Unable to create a {0} from the properties found in the JsonWebKey: '{1}', Exception '{2}'.";
public const string IDX10814 = "IDX10814: Unable to create a {0} from the properties found in the JsonWebKey: '{1}'. Missing: '{2}'.";
public const string IDX10815 = "IDX10815: Depth of JSON: '{0}' exceeds max depth of '{1}'.";

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

0 comments on commit 160f6ad

Please sign in to comment.