Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsonWebToken properties were throwing when string was 'null' #2335

Merged
merged 1 commit into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,12 @@ internal Claim GetClaim(string key, string issuer)
internal string GetStringValue(string key)
{
if (_jsonClaims.TryGetValue(key, out object obj))
{
if (obj == null)
return null;

return obj.ToString();
}

return string.Empty;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ internal void ReadToken(string encodedJson)
}
catch (Exception ex)
{
throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX14101, encodedJson.Substring(Dot2, Dot2 - Dot1)), ex));
throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX14101, encodedJson.Substring(Dot1 + 1, Dot2 - Dot1 - 1)), ex));
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
using Newtonsoft.Json.Linq;
using Xunit;

using JsonReaderException = System.Text.Json.JsonException;

namespace Microsoft.IdentityModel.JsonWebTokens.Tests
{
public class JsonWebTokenTests
Expand Down Expand Up @@ -361,6 +359,198 @@ public static TheoryData<GetPayloadValueTheoryData> CheckAudienceValuesTheoryDat
}
}

// Checks that null values are processed properly for strings, type mismatches throw expected exception.
[Theory, MemberData(nameof(GetTokenPropertyTheoryData), DisableDiscoveryEnumeration = true)]
public void GetTokenProperty(GetPayloadValueTheoryData theoryData)
{
CompareContext context = TestUtilities.WriteHeader($"{this}.GetTokenProperty", theoryData);
try
{
JsonWebToken jsonWebToken = new JsonWebToken(theoryData.Json);
string payload = Base64UrlEncoder.Decode(jsonWebToken.EncodedPayload);
PropertyInfo property = typeof(JsonWebToken).GetProperty(theoryData.PropertyName, theoryData.PropertyType);
MethodInfo method = property.GetGetMethod();
var retVal = method.Invoke(jsonWebToken, null);

theoryData.ExpectedException.ProcessNoException(context);
IdentityComparer.AreEqual(retVal, theoryData.PropertyValue, context);
}
catch (Exception ex)
{
theoryData.ExpectedException.ProcessException(ex.InnerException, context);
}

TestUtilities.AssertFailIfErrors(context);
}

public static TheoryData<GetPayloadValueTheoryData> GetTokenPropertyTheoryData
{
get
{
var theoryData = new TheoryData<GetPayloadValueTheoryData>();

#region header
theoryData.Add(new GetPayloadValueTheoryData("Alg")
{
PropertyName = "Alg",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("alg", null, "iss", "issuer")
});

theoryData.Add(new GetPayloadValueTheoryData("Alg_Int")
{
ExpectedException = new ExpectedException(typeof(System.Text.Json.JsonException), "IDX11020:"),
PropertyName = "Alg",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("alg", 1, "iss", "issuer")
});

theoryData.Add(new GetPayloadValueTheoryData("Cty")
{
PropertyName = "Cty",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("cty", null, "iss", "issuer")
});

theoryData.Add(new GetPayloadValueTheoryData("Enc")
{
PropertyName = "Enc",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("enc", null, "iss", "issuer")
});

theoryData.Add(new GetPayloadValueTheoryData("Kid")
{
PropertyName = "Kid",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("kid", null, "iss", "issuer")
});

theoryData.Add(new GetPayloadValueTheoryData("Typ")
{
PropertyName = "Typ",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("typ", null, "iss", "issuer")
});

theoryData.Add(new GetPayloadValueTheoryData("X5t")
{
PropertyName = "X5t",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("x5t", null, "iss", "issuer")
});

theoryData.Add(new GetPayloadValueTheoryData("Zip")
{
PropertyName = "Zip",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("zip", null, "iss", "issuer")
});
#endregion

#region payload
theoryData.Add(new GetPayloadValueTheoryData("Actor")
{
PropertyName = "Actor",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("actort", null)
});

theoryData.Add(new GetPayloadValueTheoryData("Audiences")
{
PropertyName = "Audiences",
PropertyType = typeof(IEnumerable<string>),
PropertyValue = new List<string>(),
Json = JsonUtilities.CreateUnsignedToken("aud", null)
});

theoryData.Add(new GetPayloadValueTheoryData("Azp")
{
PropertyName = "Azp",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("azp", null)
});

theoryData.Add(new GetPayloadValueTheoryData("Azp_Int")
{
ExpectedException = new ExpectedException(typeof(System.Text.Json.JsonException), "IDX11020:"),
PropertyName = "Azp",
PropertyType = typeof(string),
Json = JsonUtilities.CreateUnsignedToken("azp", 1)
});


theoryData.Add(new GetPayloadValueTheoryData("Issuer")
{
PropertyName = "Issuer",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("iss", null)
});

theoryData.Add(new GetPayloadValueTheoryData("IssuedAt")
{
ExpectedException = new ExpectedException(typeof(System.Text.Json.JsonException), "IDX11020:"),
PropertyName = "IssuedAt",
PropertyType = typeof(DateTime),
Json = JsonUtilities.CreateUnsignedToken("iat", null)
});

theoryData.Add(new GetPayloadValueTheoryData("IssuedAt_String")
{
ExpectedException = new ExpectedException(typeof(System.Text.Json.JsonException), "IDX11020:"),
PropertyName = "IssuedAt",
PropertyType = typeof(DateTime),
Json = JsonUtilities.CreateUnsignedToken("iat", "apple")
});

theoryData.Add(new GetPayloadValueTheoryData("Id")
{
PropertyName = "Id",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("jti", null)
});

theoryData.Add(new GetPayloadValueTheoryData("Subject")
{
PropertyName = "Subject",
PropertyType = typeof(string),
PropertyValue = null,
Json = JsonUtilities.CreateUnsignedToken("sub", null)
});

theoryData.Add(new GetPayloadValueTheoryData("ValidFrom")
{
ExpectedException = new ExpectedException(typeof(System.Text.Json.JsonException), "IDX11020:"),
PropertyName = "ValidFrom",
PropertyType = typeof(DateTime),
Json = JsonUtilities.CreateUnsignedToken("nbf", null)
});

theoryData.Add(new GetPayloadValueTheoryData("ValidTo")
{
ExpectedException = new ExpectedException(typeof(System.Text.Json.JsonException), "IDX11020:"),
PropertyName = "ValidTo",
PropertyType = typeof(DateTime),
Json = JsonUtilities.CreateUnsignedToken("exp", null)
});
#endregion

return theoryData;
}
}

// This test ensures that TryGetPayloadValue does not throw
// No need to check for equal as GetPayloadValue does that
[Theory, MemberData(nameof(GetPayloadValueTheoryData), DisableDiscoveryEnumeration = true)]
Expand All @@ -385,7 +575,7 @@ public void TryGetPayloadValue(GetPayloadValueTheoryData theoryData)
TestUtilities.AssertFailIfErrors(context);
}

// This test ensures that our roundtripping works as expected.
// This test ensures that accessing claims from the payload works as expected.
[Theory, MemberData(nameof(GetPayloadValueTheoryData), DisableDiscoveryEnumeration = true)]
public void GetPayloadValue(GetPayloadValueTheoryData theoryData)
{
Expand Down Expand Up @@ -418,7 +608,6 @@ public static TheoryData<GetPayloadValueTheoryData> GetPayloadValueTheoryData
DateTime dateTime = DateTime.UtcNow;

#region simple types from string

theoryData.Add(new GetPayloadValueTheoryData("stringFromDateTime")
{
PropertyName = "stringFromDateTime",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,16 @@ public static void SetAdditionalDataValues(IDictionary<string, object> dictionar
}

public static string CreateUnsignedToken(string key, object value)
{
return EmptyHeader + "." + CreateEncodedJson(key, value) + ".";
}

public static string CreateUnsignedToken(string headerKey, object headerValue, string payloadKey, object payloadValue)
{
return CreateEncodedJson(headerKey, headerValue) + "." + CreateEncodedJson(payloadKey, payloadValue) + ".";
}

public static string CreateEncodedJson(string key, object value)
{
Utf8JsonWriter writer = null;
using (MemoryStream memoryStream = new MemoryStream())
Expand All @@ -183,7 +193,7 @@ public static string CreateUnsignedToken(string key, object value)
writer.WriteEndObject();
writer.Flush();

return EmptyHeader + "." + Base64UrlEncoder.Encode(memoryStream.GetBuffer(), 0, (int)memoryStream.Length) + ".";
return Base64UrlEncoder.Encode(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
}
finally
{
Expand Down