From 4241ac5de4f9ed5c3af780efc642331a86ff894a Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Wed, 25 Jan 2023 00:37:31 +0100 Subject: [PATCH 01/27] Fix decoding/encoding payloads with attribute decoration #456 --- src/JWT/Builder/JwtBuilder.cs | 34 ++++++++++++- src/JWT/JWT.csproj | 2 +- .../Builder/JwtBuilderDecodeTests.cs | 48 +++++++++++++++++++ tests/JWT.Tests.Common/Models/TestData.cs | 14 ++++++ 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 36f6c61f4..3d486ec80 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -3,6 +3,7 @@ using System.Reflection; using JWT.Algorithms; using JWT.Serializers; +using Newtonsoft.Json; using static JWT.Internal.EncodingHelper; namespace JWT.Builder @@ -276,7 +277,7 @@ public string Encode(Type payloadType, object payload) EnsureCanEncode(); var dic = payloadType.GetProperties(BindingFlags.Instance | BindingFlags.Public) - .ToDictionary(prop => prop.Name, prop => prop.GetValue(payload, null)); + .ToDictionary(info => GetPropName(info, _jsonSerializerFactory), prop => prop.GetValue(payload, null)); foreach (var pair in dic) { @@ -286,6 +287,37 @@ public string Encode(Type payloadType, object payload) return Encode(); } + private static string GetPropName(MemberInfo prop, IJsonSerializerFactory jsonSerializerFactory) + { + var customAttributes = prop.GetCustomAttributes(true); + foreach (var attribute in customAttributes) + { + if (jsonSerializerFactory.Create() is JsonNetSerializer) + { + if (attribute is JsonPropertyAttribute jsonNetProperty) + { + return jsonNetProperty.PropertyName; + } + } +#if MODERN_DOTNET + else if (jsonSerializerFactory.Create() is SystemTextSerializer) + { + if (attribute is System.Text.Json.Serialization.JsonPropertyNameAttribute systemTextSerializerProperty) + { + return systemTextSerializerProperty.Name; + } + } +#endif + else + { + throw new NotSupportedException( + $"{jsonSerializerFactory.Create().GetType().Name} is not supported"); + } + } + + return prop.Name; + } + /// /// Decodes a token using the supplied dependencies. /// diff --git a/src/JWT/JWT.csproj b/src/JWT/JWT.csproj index 7513c1e4a..9038b73e5 100644 --- a/src/JWT/JWT.csproj +++ b/src/JWT/JWT.csproj @@ -20,7 +20,7 @@ Alexander Batishchev, John Sheehan, Michael Lehenbauer jwt;json;authorization CC0-1.0 - 10.0.1 + 10.0.2 10.0.0.0 10.0.0.0 JWT diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index dbafb02cf..f67bd0082 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -433,5 +433,53 @@ public void Decode_ToDictionary_Without_Serializer_Should_Throw_Exception() action.Should() .Throw(); } + + [TestMethod] + public void Encode_Decode_ToJsonNetDecoratedType_Should_UseDecoratedName_Bug456() + { + var token = JwtBuilder.Create() + .WithAlgorithm(new NoneAlgorithm()) + .WithJsonSerializer(new JsonNetSerializer()); + + var model = new TestData.TestDataJsonNetDecorated + { + AccessToken = "abc123", + }; + + var encoded = token.Encode(model); + Assert.IsNotNull(encoded); + + token = JwtBuilder.Create() + .WithAlgorithm(new NoneAlgorithm()) + .WithJsonSerializer(new JsonNetSerializer()); + + var payloadDecoded = token.Decode(encoded); + Assert.AreEqual(model.AccessToken, payloadDecoded.AccessToken); + } +#if NETSTANDARD2_0 || NET6_0 || NET7_0 + + [TestMethod] + public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecoratedName_Bug456() + { + var token = JwtBuilder.Create() + .WithAlgorithm(new NoneAlgorithm()) + .WithJsonSerializer(new SystemTextSerializer()); + + var model = new TestData.TestDataSystemTextSerializerDecorated + { + AccessToken = "abc123", + }; + + var encoded = token.Encode(model); + Assert.IsNotNull(encoded); + + token = JwtBuilder.Create() + .WithAlgorithm(new NoneAlgorithm()) + .WithJsonSerializer(new SystemTextSerializer()); + + var payloadDecoded = token.Decode(encoded); + Assert.AreEqual(model.AccessToken, payloadDecoded.AccessToken); + } +#endif } } diff --git a/tests/JWT.Tests.Common/Models/TestData.cs b/tests/JWT.Tests.Common/Models/TestData.cs index 94da079e8..9ffeb270a 100644 --- a/tests/JWT.Tests.Common/Models/TestData.cs +++ b/tests/JWT.Tests.Common/Models/TestData.cs @@ -17,6 +17,20 @@ public static class TestData Age = 33 }; + public class TestDataJsonNetDecorated + { + [Newtonsoft.Json.JsonProperty("AT")] + public string AccessToken { get; set; } + } + +#if NETSTANDARD2_0 || NET6_0 || NET7_0 + public class TestDataSystemTextSerializerDecorated + { + [System.Text.Json.Serialization.JsonPropertyName("AT")] + public string AccessToken { get; set; } + } +#endif + public const string Secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"; public const string Secret2 = "QWORIJkmQWEDIHbjhOIHAUSDFOYnUGWEYT"; From 1cf67c3249d17cb8edeb3fbf73b5598e488b74f5 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 24 Jan 2023 17:27:33 -0800 Subject: [PATCH 02/27] Update JwtBuilder.cs --- src/JWT/Builder/JwtBuilder.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 3d486ec80..13b17f19c 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -1,9 +1,14 @@ -using System; +using System; using System.Linq; using System.Reflection; using JWT.Algorithms; using JWT.Serializers; using Newtonsoft.Json; + +#if MODERN_DOTNET +using System.Text.Json.Serialization; +#endif + using static JWT.Internal.EncodingHelper; namespace JWT.Builder @@ -287,12 +292,14 @@ public string Encode(Type payloadType, object payload) return Encode(); } - private static string GetPropName(MemberInfo prop, IJsonSerializerFactory jsonSerializerFactory) + private string GetPropName(MemberInfo prop) { + var jsonSerializer = _jsonSerializerFactory.Create(); + var customAttributes = prop.GetCustomAttributes(true); foreach (var attribute in customAttributes) { - if (jsonSerializerFactory.Create() is JsonNetSerializer) + if (jsonSerializer is JsonNetSerializer) { if (attribute is JsonPropertyAttribute jsonNetProperty) { @@ -300,18 +307,17 @@ private static string GetPropName(MemberInfo prop, IJsonSerializerFactory jsonSe } } #if MODERN_DOTNET - else if (jsonSerializerFactory.Create() is SystemTextSerializer) + else if (jsonSerializer is SystemTextSerializer) { - if (attribute is System.Text.Json.Serialization.JsonPropertyNameAttribute systemTextSerializerProperty) + if (attribute is JsonPropertyNameAttribute stjProperty) { - return systemTextSerializerProperty.Name; + return stjProperty.Name; } } #endif else { - throw new NotSupportedException( - $"{jsonSerializerFactory.Create().GetType().Name} is not supported"); + throw new NotSupportedException($"{jsonSerializer.GetType().Name} is not supported"); } } From fc7807bc0c90bf84aa4abd345ecac70c890eb29e Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 24 Jan 2023 17:28:09 -0800 Subject: [PATCH 03/27] Update JwtBuilder.cs --- src/JWT/Builder/JwtBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 13b17f19c..15f940492 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -282,7 +282,7 @@ public string Encode(Type payloadType, object payload) EnsureCanEncode(); var dic = payloadType.GetProperties(BindingFlags.Instance | BindingFlags.Public) - .ToDictionary(info => GetPropName(info, _jsonSerializerFactory), prop => prop.GetValue(payload, null)); + .ToDictionary(info => GetPropName(info), prop => prop.GetValue(payload, null)); foreach (var pair in dic) { From 7c17332c9b2dfcbc0eae634f08fd57ab18a4054c Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 24 Jan 2023 17:31:08 -0800 Subject: [PATCH 04/27] Update JWT.csproj --- src/JWT/JWT.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/JWT/JWT.csproj b/src/JWT/JWT.csproj index 9038b73e5..bfb845adc 100644 --- a/src/JWT/JWT.csproj +++ b/src/JWT/JWT.csproj @@ -1,4 +1,4 @@ - + netstandard1.3;netstandard2.0;net6.0;net35;net40;net462; @@ -20,7 +20,7 @@ Alexander Batishchev, John Sheehan, Michael Lehenbauer jwt;json;authorization CC0-1.0 - 10.0.2 + 10.0.2-beta1 10.0.0.0 10.0.0.0 JWT From 23f2c6a69bf390a92cd2a850be215e7901284281 Mon Sep 17 00:00:00 2001 From: Alex Batishchev Date: Tue, 24 Jan 2023 17:33:12 -0800 Subject: [PATCH 05/27] order --- src/JWT/Builder/JwtBuilder.cs | 64 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 15f940492..96897fa25 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -292,38 +292,6 @@ public string Encode(Type payloadType, object payload) return Encode(); } - private string GetPropName(MemberInfo prop) - { - var jsonSerializer = _jsonSerializerFactory.Create(); - - var customAttributes = prop.GetCustomAttributes(true); - foreach (var attribute in customAttributes) - { - if (jsonSerializer is JsonNetSerializer) - { - if (attribute is JsonPropertyAttribute jsonNetProperty) - { - return jsonNetProperty.PropertyName; - } - } -#if MODERN_DOTNET - else if (jsonSerializer is SystemTextSerializer) - { - if (attribute is JsonPropertyNameAttribute stjProperty) - { - return stjProperty.Name; - } - } -#endif - else - { - throw new NotSupportedException($"{jsonSerializer.GetType().Name} is not supported"); - } - } - - return prop.Name; - } - /// /// Decodes a token using the supplied dependencies. /// @@ -506,5 +474,37 @@ private bool CanDecodeHeader() return true; } + + private string GetPropName(MemberInfo prop) + { + var jsonSerializer = _jsonSerializerFactory.Create(); + + var customAttributes = prop.GetCustomAttributes(inherit: true); + foreach (var attribute in customAttributes) + { + if (jsonSerializer is JsonNetSerializer) + { + if (attribute is JsonPropertyAttribute jsonNetProperty) + { + return jsonNetProperty.PropertyName; + } + } +#if MODERN_DOTNET + else if (jsonSerializer is SystemTextSerializer) + { + if (attribute is JsonPropertyNameAttribute stjProperty) + { + return stjProperty.Name; + } + } +#endif + else + { + throw new NotSupportedException($"{jsonSerializer.GetType().Name} is not supported"); + } + } + + return prop.Name; + } } } From 74a981010325ee611c4fde44b85939bd00aa7e16 Mon Sep 17 00:00:00 2001 From: Alex Batishchev Date: Tue, 24 Jan 2023 17:35:20 -0800 Subject: [PATCH 06/27] order, switch/case --- src/JWT/Builder/JwtBuilder.cs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 96897fa25..c81bb34d1 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -482,25 +482,30 @@ private string GetPropName(MemberInfo prop) var customAttributes = prop.GetCustomAttributes(inherit: true); foreach (var attribute in customAttributes) { - if (jsonSerializer is JsonNetSerializer) + switch (jsonSerializer) { - if (attribute is JsonPropertyAttribute jsonNetProperty) + case JsonNetSerializer: { - return jsonNetProperty.PropertyName; + if (attribute is JsonPropertyAttribute jsonNetProperty) + { + return jsonNetProperty.PropertyName; + } + break; } - } #if MODERN_DOTNET - else if (jsonSerializer is SystemTextSerializer) - { - if (attribute is JsonPropertyNameAttribute stjProperty) + case SystemTextSerializer: { - return stjProperty.Name; + if (attribute is JsonPropertyNameAttribute stjProperty) + { + return stjProperty.Name; + } + break; } - } #endif - else - { - throw new NotSupportedException($"{jsonSerializer.GetType().Name} is not supported"); + default: + { + throw new NotSupportedException($"{jsonSerializer.GetType()} is not supported"); + } } } From 223ac2d81e33d89799103ad1ed8c44541f91289d Mon Sep 17 00:00:00 2001 From: Alex Batishchev Date: Tue, 24 Jan 2023 17:43:50 -0800 Subject: [PATCH 07/27] || NET7_0 --- tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs | 2 +- tests/JWT.Tests.Common/Models/TestData.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index f67bd0082..fe245f8ad 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -456,7 +456,7 @@ public void Encode_Decode_ToJsonNetDecoratedType_Should_UseDecoratedName_Bug456( var payloadDecoded = token.Decode(encoded); Assert.AreEqual(model.AccessToken, payloadDecoded.AccessToken); } -#if NETSTANDARD2_0 || NET6_0 || NET7_0 +#if NETSTANDARD2_0 || NET6_0 [TestMethod] public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecoratedName_Bug456() diff --git a/tests/JWT.Tests.Common/Models/TestData.cs b/tests/JWT.Tests.Common/Models/TestData.cs index 9ffeb270a..93e58c356 100644 --- a/tests/JWT.Tests.Common/Models/TestData.cs +++ b/tests/JWT.Tests.Common/Models/TestData.cs @@ -23,7 +23,7 @@ public class TestDataJsonNetDecorated public string AccessToken { get; set; } } -#if NETSTANDARD2_0 || NET6_0 || NET7_0 +#if NETSTANDARD2_0 || NET6_0 public class TestDataSystemTextSerializerDecorated { [System.Text.Json.Serialization.JsonPropertyName("AT")] From e519d8fb9904f96eb68e0d47aa462d68de786fbe Mon Sep 17 00:00:00 2001 From: Alex Batishchev Date: Tue, 24 Jan 2023 17:45:11 -0800 Subject: [PATCH 08/27] City --- .../JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs | 10 +++++----- tests/JWT.Tests.Common/Models/TestData.cs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index fe245f8ad..bf256a151 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -443,7 +443,7 @@ public void Encode_Decode_ToJsonNetDecoratedType_Should_UseDecoratedName_Bug456( var model = new TestData.TestDataJsonNetDecorated { - AccessToken = "abc123", + City = "Amsterdam", }; var encoded = token.Encode(model); @@ -454,10 +454,10 @@ public void Encode_Decode_ToJsonNetDecoratedType_Should_UseDecoratedName_Bug456( .WithJsonSerializer(new JsonNetSerializer()); var payloadDecoded = token.Decode(encoded); - Assert.AreEqual(model.AccessToken, payloadDecoded.AccessToken); + Assert.AreEqual(model.City, payloadDecoded.City); } -#if NETSTANDARD2_0 || NET6_0 +#if NETSTANDARD2_0 || NET6_0 [TestMethod] public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecoratedName_Bug456() { @@ -467,7 +467,7 @@ public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecorate var model = new TestData.TestDataSystemTextSerializerDecorated { - AccessToken = "abc123", + City = "Amsterdam", }; var encoded = token.Encode(model); @@ -478,7 +478,7 @@ public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecorate .WithJsonSerializer(new SystemTextSerializer()); var payloadDecoded = token.Decode(encoded); - Assert.AreEqual(model.AccessToken, payloadDecoded.AccessToken); + Assert.AreEqual(model.City, payloadDecoded.City); } #endif } diff --git a/tests/JWT.Tests.Common/Models/TestData.cs b/tests/JWT.Tests.Common/Models/TestData.cs index 93e58c356..529c91202 100644 --- a/tests/JWT.Tests.Common/Models/TestData.cs +++ b/tests/JWT.Tests.Common/Models/TestData.cs @@ -20,14 +20,14 @@ public static class TestData public class TestDataJsonNetDecorated { [Newtonsoft.Json.JsonProperty("AT")] - public string AccessToken { get; set; } + public string City { get; set; } } #if NETSTANDARD2_0 || NET6_0 public class TestDataSystemTextSerializerDecorated { [System.Text.Json.Serialization.JsonPropertyName("AT")] - public string AccessToken { get; set; } + public string City { get; set; } } #endif From 4fcbc1557196152ec898c06863b6842d75849059 Mon Sep 17 00:00:00 2001 From: Alex Batishchev Date: Tue, 24 Jan 2023 17:47:50 -0800 Subject: [PATCH 09/27] tests --- .../Builder/JwtBuilderDecodeTests.cs | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index bf256a151..9eb4cec53 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -437,48 +437,54 @@ public void Decode_ToDictionary_Without_Serializer_Should_Throw_Exception() [TestMethod] public void Encode_Decode_ToJsonNetDecoratedType_Should_UseDecoratedName_Bug456() { + var serializer = new JsonNetSerializer(); + var alg = new NoneAlgorithm(); + var token = JwtBuilder.Create() - .WithAlgorithm(new NoneAlgorithm()) - .WithJsonSerializer(new JsonNetSerializer()); + .WithAlgorithm(alg) + .WithJsonSerializer(serializer); - var model = new TestData.TestDataJsonNetDecorated + var expected = new TestData.TestDataJsonNetDecorated { City = "Amsterdam", }; - var encoded = token.Encode(model); - Assert.IsNotNull(encoded); + var encoded = token.Encode(expected); + encoded.Should().NotBeNullOrEmpty(); token = JwtBuilder.Create() - .WithAlgorithm(new NoneAlgorithm()) - .WithJsonSerializer(new JsonNetSerializer()); + .WithAlgorithm(alg) + .WithJsonSerializer(serializer); - var payloadDecoded = token.Decode(encoded); - Assert.AreEqual(model.City, payloadDecoded.City); + var actual = token.Decode(encoded); + actual.Should().BeEquivalentTo(expected); } #if NETSTANDARD2_0 || NET6_0 [TestMethod] public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecoratedName_Bug456() { + var serializer = new SystemTextSerializer(); + var alg = new NoneAlgorithm(); + var token = JwtBuilder.Create() - .WithAlgorithm(new NoneAlgorithm()) - .WithJsonSerializer(new SystemTextSerializer()); + .WithAlgorithm(alg) + .WithJsonSerializer(serializer); - var model = new TestData.TestDataSystemTextSerializerDecorated + var expected = new TestData.TestDataSystemTextSerializerDecorated { City = "Amsterdam", }; - var encoded = token.Encode(model); - Assert.IsNotNull(encoded); + var encoded = token.Encode(expected); + encoded.Should().NotBeNullOrEmpty(); token = JwtBuilder.Create() - .WithAlgorithm(new NoneAlgorithm()) - .WithJsonSerializer(new SystemTextSerializer()); + .WithAlgorithm(alg) + .WithJsonSerializer(serializer); - var payloadDecoded = token.Decode(encoded); - Assert.AreEqual(model.City, payloadDecoded.City); + var actual = token.Decode(encoded); + actual.Should().BeEquivalentTo(expected); } #endif } From c8a78e9d43441fcfc2c35e332fb92ddab524e326 Mon Sep 17 00:00:00 2001 From: Alex Batishchev Date: Tue, 24 Jan 2023 17:48:45 -0800 Subject: [PATCH 10/27] prop --- src/JWT/Builder/JwtBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index c81bb34d1..a2bbeffe9 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -282,7 +282,7 @@ public string Encode(Type payloadType, object payload) EnsureCanEncode(); var dic = payloadType.GetProperties(BindingFlags.Instance | BindingFlags.Public) - .ToDictionary(info => GetPropName(info), prop => prop.GetValue(payload, null)); + .ToDictionary(prop => GetPropName(prop), prop => prop.GetValue(payload, null)); foreach (var pair in dic) { From 03cc94072a926c62495e302b8fb36d0095b01a0f Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Wed, 25 Jan 2023 12:03:32 +0100 Subject: [PATCH 11/27] Fallback to property-name if serializer is unknown added test for stjSerializer for Encode nested property --- src/JWT/Builder/JwtBuilder.cs | 2 +- .../Builder/JwtBuilderEncodeTests.cs | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index a2bbeffe9..437765b43 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -504,7 +504,7 @@ private string GetPropName(MemberInfo prop) #endif default: { - throw new NotSupportedException($"{jsonSerializer.GetType()} is not supported"); + return prop.Name; } } } diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs index 2dd229f23..6be3df4aa 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs @@ -382,6 +382,35 @@ public void Encode_With_Secret_Should_Return_Valid_Token_Using_Json_Net() } #if NETSTANDARD2_0 || NET6_0_OR_GREATER + + [TestMethod] + public void Encode_Should_Return_Token_With_Custom_Extra_Headers_Full_Payload_SystemTextSerializer() + { + var serializer = new SystemTextSerializer(); + + const string key = TestData.Secret; + + var token = JwtBuilder.Create() + .WithAlgorithm(TestData.HMACSHA256Algorithm) + .WithSecret(key) + .WithJsonSerializer(serializer) + .AddHeader("version", 1) + .Encode( + new + { + ExtraClaim = new + { + NestedProperty1 = "Foo", + NestedProperty2 = 3 + }, + FirstName = "Jesus", + Age = 33 + }); + + token.Should() + .Be(TestData.TokenWithCustomTypeHeader3AndClaimNested, "because the same data encoded with the same key must result in the same token"); + } + [TestMethod] public void Encode_Test_Bug438() { From 827fcf7cd5dfa80416c1d56daa462bb69af2d3df Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Wed, 25 Jan 2023 13:18:50 +0100 Subject: [PATCH 12/27] Added more tests for complex claims --- src/JWT/Builder/JwtBuilder.cs | 8 +++ .../Builder/JwtBuilderDecodeTests.cs | 61 +++++++++++++++++++ tests/JWT.Tests.Common/Models/TestData.cs | 10 +++ 3 files changed, 79 insertions(+) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 437765b43..08c46b8df 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -326,6 +326,14 @@ public T DecodeHeader(string token) return _decoder.DecodeHeader(token); } + public object Decode(string token, Type type) + { + EnsureCanDecode(); + + return _decoder.DecodeToObject(type, token, _secrets, _valParams.ValidateSignature); + } + + /// /// Decodes a token using the supplied dependencies. /// diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index 9eb4cec53..78a8bdc21 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -460,6 +460,39 @@ public void Encode_Decode_ToJsonNetDecoratedType_Should_UseDecoratedName_Bug456( actual.Should().BeEquivalentTo(expected); } + [TestMethod] + public void Encode_Decode_Should_Return_Token_Nested_Data_ShouldRespectAttributes() + { + var serializer = new JsonNetSerializer(); + var alg = new NoneAlgorithm(); + + var expected = new TestData.TestDataJsonNetDecorated + { + City = "Amsterdam", + }; + + var encoded = JwtBuilder.Create() + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .AddClaim("Data", expected) + .Encode(); + + encoded.Should().NotBeNullOrEmpty(); + Console.WriteLine(encoded); + var jwtBuilder = JwtBuilder.Create() + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .WithJsonSerializer(serializer); + + var payloadType = new TestData.PayloadWithNestedJsonNetData + { + Data = default + }; + + var actual = (TestData.PayloadWithNestedJsonNetData)jwtBuilder.Decode(encoded, payloadType.GetType()); + actual.Data.Should().BeEquivalentTo(expected); + } + #if NETSTANDARD2_0 || NET6_0 [TestMethod] public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecoratedName_Bug456() @@ -486,6 +519,34 @@ public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecorate var actual = token.Decode(encoded); actual.Should().BeEquivalentTo(expected); } + + [TestMethod] + public void Encode_Decode_Should_Return_Token_Nested_Data_ShouldRespectAttributes_SystemTextSerializer() + { + var serializer = new SystemTextSerializer(); + var alg = new NoneAlgorithm(); + + var expected = new TestData.TestDataSystemTextSerializerDecorated + { + City = "Amsterdam", + }; + + var encoded = JwtBuilder.Create() + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .AddClaim("Data", expected) + .Encode(); + + encoded.Should().NotBeNullOrEmpty(); + Console.WriteLine(encoded); + var jwtBuilder = JwtBuilder.Create() + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .WithJsonSerializer(serializer); + + var actual = jwtBuilder.Decode(encoded); + actual.Data.Should().BeEquivalentTo(expected); + } #endif } } diff --git a/tests/JWT.Tests.Common/Models/TestData.cs b/tests/JWT.Tests.Common/Models/TestData.cs index 529c91202..04761ae74 100644 --- a/tests/JWT.Tests.Common/Models/TestData.cs +++ b/tests/JWT.Tests.Common/Models/TestData.cs @@ -17,6 +17,11 @@ public static class TestData Age = 33 }; + public class PayloadWithNestedJsonNetData + { + public TestDataJsonNetDecorated Data { get; set; } + } + public class TestDataJsonNetDecorated { [Newtonsoft.Json.JsonProperty("AT")] @@ -24,6 +29,11 @@ public class TestDataJsonNetDecorated } #if NETSTANDARD2_0 || NET6_0 + public class PayloadWithNestedSystemTextSerializerData + { + public TestDataSystemTextSerializerDecorated Data { get; set; } + } + public class TestDataSystemTextSerializerDecorated { [System.Text.Json.Serialization.JsonPropertyName("AT")] From 3a5945aa8dd8d7c6eeaf9d7a9d60b0d0725b8a25 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Wed, 25 Jan 2023 14:06:06 -0800 Subject: [PATCH 13/27] Update JwtBuilderDecodeTests.cs --- .../Builder/JwtBuilderDecodeTests.cs | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index 78a8bdc21..a00fb3107 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using FluentAssertions; using JWT.Algorithms; @@ -480,7 +480,7 @@ public void Encode_Decode_Should_Return_Token_Nested_Data_ShouldRespectAttribute encoded.Should().NotBeNullOrEmpty(); Console.WriteLine(encoded); var jwtBuilder = JwtBuilder.Create() - .WithAlgorithm(alg) + .WithAlgorithm(alg) .WithJsonSerializer(serializer) .WithJsonSerializer(serializer); @@ -500,23 +500,21 @@ public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecorate var serializer = new SystemTextSerializer(); var alg = new NoneAlgorithm(); - var token = JwtBuilder.Create() - .WithAlgorithm(alg) - .WithJsonSerializer(serializer); - var expected = new TestData.TestDataSystemTextSerializerDecorated { City = "Amsterdam", }; - var encoded = token.Encode(expected); + var encoded = JwtBuilder.Create() + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .Encode(expected); encoded.Should().NotBeNullOrEmpty(); - token = JwtBuilder.Create() - .WithAlgorithm(alg) - .WithJsonSerializer(serializer); - - var actual = token.Decode(encoded); + var actual = JwtBuilder.Create() + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .Decode(encoded); actual.Should().BeEquivalentTo(expected); } @@ -532,19 +530,17 @@ public void Encode_Decode_Should_Return_Token_Nested_Data_ShouldRespectAttribute }; var encoded = JwtBuilder.Create() - .WithAlgorithm(alg) - .WithJsonSerializer(serializer) - .AddClaim("Data", expected) - .Encode(); - + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .AddClaim("Data", expected) + .Encode(); encoded.Should().NotBeNullOrEmpty(); - Console.WriteLine(encoded); - var jwtBuilder = JwtBuilder.Create() - .WithAlgorithm(alg) - .WithJsonSerializer(serializer) - .WithJsonSerializer(serializer); - var actual = jwtBuilder.Decode(encoded); + var actual = JwtBuilder.Create() + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .WithJsonSerializer(serializer) + .Decode(encoded); actual.Data.Should().BeEquivalentTo(expected); } #endif From ce524cfd45209269aae4186b8a6b838e7a4896bd Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Wed, 25 Jan 2023 14:06:52 -0800 Subject: [PATCH 14/27] Update TestData.cs --- tests/JWT.Tests.Common/Models/TestData.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/JWT.Tests.Common/Models/TestData.cs b/tests/JWT.Tests.Common/Models/TestData.cs index 04761ae74..3db70255c 100644 --- a/tests/JWT.Tests.Common/Models/TestData.cs +++ b/tests/JWT.Tests.Common/Models/TestData.cs @@ -3,7 +3,7 @@ using System.Security.Cryptography.X509Certificates; using JWT.Algorithms; -#if NETSTANDARD2_1 || NET6_0 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER using System.Security.Cryptography; #endif @@ -92,7 +92,7 @@ public class TestDataSystemTextSerializerDecorated public static readonly X509Certificate2 CertificateWithPublicKeyEcdsa = new X509Certificate2( Convert.FromBase64String(ServerPublicKeyEcdsa)); -#if NETSTANDARD2_1 || NET6_0 +#if NETSTANDARD2_1 || NET6_0_OR_GREATER public static readonly X509Certificate2 CertificateWithPrivateKey = CreateCertificate(); private static X509Certificate2 CreateCertificate() @@ -107,4 +107,4 @@ private static X509Certificate2 CreateCertificate() } #endif } -} \ No newline at end of file +} From 0ae353cdd60fd1b84fede4879da0d3f6b1e03449 Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Wed, 25 Jan 2023 23:45:21 +0100 Subject: [PATCH 15/27] WIP JwtEncoder.Encode() now accepts a list of payloads so we can use both claims and payload --- src/JWT/Builder/JwtBuilder.cs | 51 +++---------------- src/JWT/IJsonSerializer.cs | 8 +++ src/JWT/IJwtEncoder.cs | 2 + src/JWT/JwtEncoder.cs | 41 +++++++++++++++ src/JWT/Serializers/JsonNetSerializer.cs | 10 ++++ src/JWT/Serializers/SystemTextSerializer.cs | 28 +++++++++- .../Builder/JwtBuilderEncodeTests.cs | 19 +------ 7 files changed, 96 insertions(+), 63 deletions(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 08c46b8df..92caafc12 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -278,18 +278,16 @@ public string Encode(Type payloadType, object payload) throw new ArgumentNullException(nameof(payloadType)); if (payload is null) throw new ArgumentNullException(nameof(payload)); - - EnsureCanEncode(); - var dic = payloadType.GetProperties(BindingFlags.Instance | BindingFlags.Public) - .ToDictionary(prop => GetPropName(prop), prop => prop.GetValue(payload, null)); - - foreach (var pair in dic) + // Preserve old behaviour checking the type, is it needed? + if (payloadType != payload.GetType()) { - _jwt.Payload.Add(pair.Key, pair.Value); + throw new NotSupportedException("Object does not match target type."); } + + EnsureCanEncode(); - return Encode(); + return _encoder.Encode(_jwt.Header, new[] {_jwt.Payload, payload}, _secrets?[0]); } /// @@ -482,42 +480,5 @@ private bool CanDecodeHeader() return true; } - - private string GetPropName(MemberInfo prop) - { - var jsonSerializer = _jsonSerializerFactory.Create(); - - var customAttributes = prop.GetCustomAttributes(inherit: true); - foreach (var attribute in customAttributes) - { - switch (jsonSerializer) - { - case JsonNetSerializer: - { - if (attribute is JsonPropertyAttribute jsonNetProperty) - { - return jsonNetProperty.PropertyName; - } - break; - } -#if MODERN_DOTNET - case SystemTextSerializer: - { - if (attribute is JsonPropertyNameAttribute stjProperty) - { - return stjProperty.Name; - } - break; - } -#endif - default: - { - return prop.Name; - } - } - } - - return prop.Name; - } } } diff --git a/src/JWT/IJsonSerializer.cs b/src/JWT/IJsonSerializer.cs index 12007ff5c..0ebbefe6d 100644 --- a/src/JWT/IJsonSerializer.cs +++ b/src/JWT/IJsonSerializer.cs @@ -21,6 +21,14 @@ public interface IJsonSerializer /// The JSON string deserialize. /// Strongly-typed object. object Deserialize(Type type, string json); + + /// + /// Merges two objects into a single JSON string. + /// + /// The first object to serialize + /// The second object to serialize, note that any existing property in obj1 will be + /// JSON string + string MergeObjects(object obj1, object obj2); } /// diff --git a/src/JWT/IJwtEncoder.cs b/src/JWT/IJwtEncoder.cs index e37835c59..492192939 100644 --- a/src/JWT/IJwtEncoder.cs +++ b/src/JWT/IJwtEncoder.cs @@ -18,6 +18,8 @@ public interface IJwtEncoder /// The key bytes used to sign the token /// The generated JWT string Encode(IDictionary extraHeaders, object payload, byte[] key); + + string Encode(IDictionary extraHeaders, object[] payloads, byte[] key); } /// diff --git a/src/JWT/JwtEncoder.cs b/src/JWT/JwtEncoder.cs index 126e9f7c1..02dd0716c 100644 --- a/src/JWT/JwtEncoder.cs +++ b/src/JWT/JwtEncoder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using JWT.Algorithms; using static JWT.Internal.EncodingHelper; @@ -39,6 +40,46 @@ public JwtEncoder(IJwtAlgorithm algorithm, IJsonSerializer jsonSerializer, IBase { } + public string Encode(IDictionary extraHeaders, object[] payloads, byte[] key) + { + if (payloads is null) + throw new ArgumentNullException(nameof(payloads)); + + if (!payloads.Any() || payloads.Length != 2) + { + throw new NotSupportedException("Only two payloads are supported"); + } + + var algorithm = _algFactory.Create(null); + if (algorithm is null) + throw new ArgumentNullException(nameof(algorithm)); + if (!algorithm.IsAsymmetric() && key is null && algorithm is not NoneAlgorithm) + throw new ArgumentNullException(nameof(key)); + + var header = extraHeaders is null ? + new Dictionary(2, StringComparer.OrdinalIgnoreCase) : + new Dictionary(extraHeaders, StringComparer.OrdinalIgnoreCase); + + if (!header.ContainsKey("typ")) + { + header.Add("typ", "JWT"); + } + header.Add("alg", algorithm.Name); + + var headerBytes = GetBytes(_jsonSerializer.Serialize(header)); + + var payloadBytes = GetBytes(_jsonSerializer.MergeObjects(payloads[0], payloads[1])); + + var headerSegment = _urlEncoder.Encode(headerBytes); + var payloadSegment = _urlEncoder.Encode(payloadBytes); + + var stringToSign = headerSegment + "." + payloadSegment; + var bytesToSign = GetBytes(stringToSign); + + var signatureSegment = GetSignatureSegment(algorithm, key, bytesToSign); + return stringToSign + "." + signatureSegment; + } + /// /// public string Encode(IDictionary extraHeaders, object payload, byte[] key) diff --git a/src/JWT/Serializers/JsonNetSerializer.cs b/src/JWT/Serializers/JsonNetSerializer.cs index 4dbb02115..2190417d7 100644 --- a/src/JWT/Serializers/JsonNetSerializer.cs +++ b/src/JWT/Serializers/JsonNetSerializer.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace JWT.Serializers { @@ -58,5 +59,14 @@ public object Deserialize(Type type, string json) using var jsonReader = new JsonTextReader(stringReader); return _serializer.Deserialize(jsonReader, type); } + + public string MergeObjects(object obj1, object obj2) + { + var jObject1 = JObject.Parse(Serialize(obj1)); + var jObject2 = JObject.Parse(Serialize(obj2)); + + jObject1.Merge(jObject2); + return jObject1.ToString(Formatting.None); + } } } diff --git a/src/JWT/Serializers/SystemTextSerializer.cs b/src/JWT/Serializers/SystemTextSerializer.cs index 84d9849d0..9461dc1af 100644 --- a/src/JWT/Serializers/SystemTextSerializer.cs +++ b/src/JWT/Serializers/SystemTextSerializer.cs @@ -1,6 +1,8 @@ #if MODERN_DOTNET using System; +using System.Linq; using System.Text.Json; +using System.Text.Json.Nodes; using JWT.Serializers.Converters; namespace JWT.Serializers @@ -19,7 +21,7 @@ public class SystemTextSerializer : IJsonSerializer new DictionaryStringObjectJsonConverterCustomWrite() } }; - + /// /// public string Serialize(object obj) @@ -43,6 +45,30 @@ public object Deserialize(Type type, string json) return JsonSerializer.Deserialize(json, type, _optionsForDeserialize); } + + public string MergeObjects(object obj1, object obj2) + { + if (obj1 == null) + { + throw new ArgumentNullException(nameof(obj1)); + } + + if (obj2 == null) + { + throw new ArgumentNullException(nameof(obj2)); + } + + var jsonNode1 = JsonNode.Parse(Serialize(obj1)); + var jsonNode2 = JsonNode.Parse(Serialize(obj2)); + + foreach (var property in jsonNode2.AsObject().ToArray()) + { + jsonNode2.AsObject().Remove(property.Key); + jsonNode1[property.Key] = property.Value; + } + + return jsonNode1.ToJsonString(_optionsForSerialize); + } } } #endif diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs index 6be3df4aa..3771e2f60 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs @@ -290,25 +290,10 @@ public void Encode_Should_Return_ThrowTargetException_Encode_TypesMatch() .AddClaim("ExtraClaim", new { NestedProperty1 = "Foo", NestedProperty2 = 3 }) .Encode(typeof(string), TestData.Customer); - if (IsRunningOnMono()) - { - action.Should() - .Throw("Exception has been thrown by the target of an invocation."); - } - else - { - action.Should() - .Throw("Object does not match target type."); - } + action.Should() + .Throw("Object does not match target type."); } - /// - /// Copied from: https://stackoverflow.com/a/7077620/2890855 - /// - /// - private static bool IsRunningOnMono() => - Type.GetType("Mono.Runtime") is not null; - [TestMethod] public void Encode_Should_Return_Token_With_Custom_Extra_Headers_Full_Payload2() { From 73948aa078b6fcc85cc8c459e8bfea05848f18ff Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Sat, 28 Jan 2023 00:05:01 +0100 Subject: [PATCH 16/27] Revert "WIP JwtEncoder.Encode() now accepts a list of payloads so we can use both claims and payload" This reverts commit 341da1cb0c06162a3a67099cc0ff7b3f67e5e786. --- src/JWT/Builder/JwtBuilder.cs | 51 ++++++++++++++++--- src/JWT/IJsonSerializer.cs | 8 --- src/JWT/IJwtEncoder.cs | 2 - src/JWT/JwtEncoder.cs | 41 --------------- src/JWT/Serializers/JsonNetSerializer.cs | 10 ---- src/JWT/Serializers/SystemTextSerializer.cs | 28 +--------- .../Builder/JwtBuilderEncodeTests.cs | 19 ++++++- 7 files changed, 63 insertions(+), 96 deletions(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 92caafc12..08c46b8df 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -278,16 +278,18 @@ public string Encode(Type payloadType, object payload) throw new ArgumentNullException(nameof(payloadType)); if (payload is null) throw new ArgumentNullException(nameof(payload)); + + EnsureCanEncode(); - // Preserve old behaviour checking the type, is it needed? - if (payloadType != payload.GetType()) + var dic = payloadType.GetProperties(BindingFlags.Instance | BindingFlags.Public) + .ToDictionary(prop => GetPropName(prop), prop => prop.GetValue(payload, null)); + + foreach (var pair in dic) { - throw new NotSupportedException("Object does not match target type."); + _jwt.Payload.Add(pair.Key, pair.Value); } - - EnsureCanEncode(); - return _encoder.Encode(_jwt.Header, new[] {_jwt.Payload, payload}, _secrets?[0]); + return Encode(); } /// @@ -480,5 +482,42 @@ private bool CanDecodeHeader() return true; } + + private string GetPropName(MemberInfo prop) + { + var jsonSerializer = _jsonSerializerFactory.Create(); + + var customAttributes = prop.GetCustomAttributes(inherit: true); + foreach (var attribute in customAttributes) + { + switch (jsonSerializer) + { + case JsonNetSerializer: + { + if (attribute is JsonPropertyAttribute jsonNetProperty) + { + return jsonNetProperty.PropertyName; + } + break; + } +#if MODERN_DOTNET + case SystemTextSerializer: + { + if (attribute is JsonPropertyNameAttribute stjProperty) + { + return stjProperty.Name; + } + break; + } +#endif + default: + { + return prop.Name; + } + } + } + + return prop.Name; + } } } diff --git a/src/JWT/IJsonSerializer.cs b/src/JWT/IJsonSerializer.cs index 0ebbefe6d..12007ff5c 100644 --- a/src/JWT/IJsonSerializer.cs +++ b/src/JWT/IJsonSerializer.cs @@ -21,14 +21,6 @@ public interface IJsonSerializer /// The JSON string deserialize. /// Strongly-typed object. object Deserialize(Type type, string json); - - /// - /// Merges two objects into a single JSON string. - /// - /// The first object to serialize - /// The second object to serialize, note that any existing property in obj1 will be - /// JSON string - string MergeObjects(object obj1, object obj2); } /// diff --git a/src/JWT/IJwtEncoder.cs b/src/JWT/IJwtEncoder.cs index 492192939..e37835c59 100644 --- a/src/JWT/IJwtEncoder.cs +++ b/src/JWT/IJwtEncoder.cs @@ -18,8 +18,6 @@ public interface IJwtEncoder /// The key bytes used to sign the token /// The generated JWT string Encode(IDictionary extraHeaders, object payload, byte[] key); - - string Encode(IDictionary extraHeaders, object[] payloads, byte[] key); } /// diff --git a/src/JWT/JwtEncoder.cs b/src/JWT/JwtEncoder.cs index 02dd0716c..126e9f7c1 100644 --- a/src/JWT/JwtEncoder.cs +++ b/src/JWT/JwtEncoder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using JWT.Algorithms; using static JWT.Internal.EncodingHelper; @@ -40,46 +39,6 @@ public JwtEncoder(IJwtAlgorithm algorithm, IJsonSerializer jsonSerializer, IBase { } - public string Encode(IDictionary extraHeaders, object[] payloads, byte[] key) - { - if (payloads is null) - throw new ArgumentNullException(nameof(payloads)); - - if (!payloads.Any() || payloads.Length != 2) - { - throw new NotSupportedException("Only two payloads are supported"); - } - - var algorithm = _algFactory.Create(null); - if (algorithm is null) - throw new ArgumentNullException(nameof(algorithm)); - if (!algorithm.IsAsymmetric() && key is null && algorithm is not NoneAlgorithm) - throw new ArgumentNullException(nameof(key)); - - var header = extraHeaders is null ? - new Dictionary(2, StringComparer.OrdinalIgnoreCase) : - new Dictionary(extraHeaders, StringComparer.OrdinalIgnoreCase); - - if (!header.ContainsKey("typ")) - { - header.Add("typ", "JWT"); - } - header.Add("alg", algorithm.Name); - - var headerBytes = GetBytes(_jsonSerializer.Serialize(header)); - - var payloadBytes = GetBytes(_jsonSerializer.MergeObjects(payloads[0], payloads[1])); - - var headerSegment = _urlEncoder.Encode(headerBytes); - var payloadSegment = _urlEncoder.Encode(payloadBytes); - - var stringToSign = headerSegment + "." + payloadSegment; - var bytesToSign = GetBytes(stringToSign); - - var signatureSegment = GetSignatureSegment(algorithm, key, bytesToSign); - return stringToSign + "." + signatureSegment; - } - /// /// public string Encode(IDictionary extraHeaders, object payload, byte[] key) diff --git a/src/JWT/Serializers/JsonNetSerializer.cs b/src/JWT/Serializers/JsonNetSerializer.cs index 2190417d7..4dbb02115 100644 --- a/src/JWT/Serializers/JsonNetSerializer.cs +++ b/src/JWT/Serializers/JsonNetSerializer.cs @@ -2,7 +2,6 @@ using System.IO; using System.Text; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace JWT.Serializers { @@ -59,14 +58,5 @@ public object Deserialize(Type type, string json) using var jsonReader = new JsonTextReader(stringReader); return _serializer.Deserialize(jsonReader, type); } - - public string MergeObjects(object obj1, object obj2) - { - var jObject1 = JObject.Parse(Serialize(obj1)); - var jObject2 = JObject.Parse(Serialize(obj2)); - - jObject1.Merge(jObject2); - return jObject1.ToString(Formatting.None); - } } } diff --git a/src/JWT/Serializers/SystemTextSerializer.cs b/src/JWT/Serializers/SystemTextSerializer.cs index 9461dc1af..84d9849d0 100644 --- a/src/JWT/Serializers/SystemTextSerializer.cs +++ b/src/JWT/Serializers/SystemTextSerializer.cs @@ -1,8 +1,6 @@ #if MODERN_DOTNET using System; -using System.Linq; using System.Text.Json; -using System.Text.Json.Nodes; using JWT.Serializers.Converters; namespace JWT.Serializers @@ -21,7 +19,7 @@ public class SystemTextSerializer : IJsonSerializer new DictionaryStringObjectJsonConverterCustomWrite() } }; - + /// /// public string Serialize(object obj) @@ -45,30 +43,6 @@ public object Deserialize(Type type, string json) return JsonSerializer.Deserialize(json, type, _optionsForDeserialize); } - - public string MergeObjects(object obj1, object obj2) - { - if (obj1 == null) - { - throw new ArgumentNullException(nameof(obj1)); - } - - if (obj2 == null) - { - throw new ArgumentNullException(nameof(obj2)); - } - - var jsonNode1 = JsonNode.Parse(Serialize(obj1)); - var jsonNode2 = JsonNode.Parse(Serialize(obj2)); - - foreach (var property in jsonNode2.AsObject().ToArray()) - { - jsonNode2.AsObject().Remove(property.Key); - jsonNode1[property.Key] = property.Value; - } - - return jsonNode1.ToJsonString(_optionsForSerialize); - } } } #endif diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs index 3771e2f60..6be3df4aa 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs @@ -290,10 +290,25 @@ public void Encode_Should_Return_ThrowTargetException_Encode_TypesMatch() .AddClaim("ExtraClaim", new { NestedProperty1 = "Foo", NestedProperty2 = 3 }) .Encode(typeof(string), TestData.Customer); - action.Should() - .Throw("Object does not match target type."); + if (IsRunningOnMono()) + { + action.Should() + .Throw("Exception has been thrown by the target of an invocation."); + } + else + { + action.Should() + .Throw("Object does not match target type."); + } } + /// + /// Copied from: https://stackoverflow.com/a/7077620/2890855 + /// + /// + private static bool IsRunningOnMono() => + Type.GetType("Mono.Runtime") is not null; + [TestMethod] public void Encode_Should_Return_Token_With_Custom_Extra_Headers_Full_Payload2() { From 8b9ac59501313b94107bca1b4916441d5a043e11 Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Sat, 28 Jan 2023 00:10:29 +0100 Subject: [PATCH 17/27] UnitTest count for Net60 and Net70 is now the same --- tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index a00fb3107..c63400822 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using FluentAssertions; using JWT.Algorithms; @@ -493,7 +493,7 @@ public void Encode_Decode_Should_Return_Token_Nested_Data_ShouldRespectAttribute actual.Data.Should().BeEquivalentTo(expected); } -#if NETSTANDARD2_0 || NET6_0 +#if NETSTANDARD2_0 || NET6_0_OR_GREATER [TestMethod] public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecoratedName_Bug456() { From 5c2787b22fdf0e638870f9296e72076514622432 Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Wed, 1 Feb 2023 00:13:13 +0100 Subject: [PATCH 18/27] Disallow Encode(payload) with AddClaim(s) --- src/JWT/Builder/JwtBuilder.cs | 19 ++--- .../Builder/JwtBuilderEncodeTests.cs | 84 ++++++------------- 2 files changed, 32 insertions(+), 71 deletions(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 08c46b8df..7008eaa3d 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -269,27 +269,20 @@ public string Encode() return _encoder.Encode(_jwt.Header, _jwt.Payload, _secrets?[0]); } - public string Encode(T payload) => - Encode(typeof(T), payload); - - public string Encode(Type payloadType, object payload) + public string Encode(object payload) { - if (payloadType is null) - throw new ArgumentNullException(nameof(payloadType)); if (payload is null) throw new ArgumentNullException(nameof(payload)); - - EnsureCanEncode(); - var dic = payloadType.GetProperties(BindingFlags.Instance | BindingFlags.Public) - .ToDictionary(prop => GetPropName(prop), prop => prop.GetValue(payload, null)); + EnsureCanEncode(); - foreach (var pair in dic) + if (_jwt.Payload.Any()) { - _jwt.Payload.Add(pair.Key, pair.Value); + throw new NotSupportedException( + "Having JWT as a key-value store and implicit payload is not supported."); } - return Encode(); + return _encoder.Encode(_jwt.Header, payload, _secrets?[0]); } /// diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs index 6be3df4aa..7a3787943 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs @@ -230,78 +230,46 @@ public void Encode_Should_Return_Token_With_Custom_Extra_Headers_Full_Payload() } [TestMethod] - public void Encode_Should_Return_Token_With_Custom_Extra_Headers_Full_Payload_And_Claims() + public void Encode_Should_Throw_NotSupportedException_When_Using_EncodePayload_WithAddClaim() { const string key = TestData.Secret; - var token = JwtBuilder.Create() - .WithAlgorithm(TestData.HMACSHA256Algorithm) - .WithSecret(key) - .AddHeader("version", 1) - .AddClaim("ExtraClaim", "ValueClaim") - .Encode(TestData.Customer); - - token.Should() - .Be(TestData.TokenWithCustomTypeHeader3AndClaim, "because the same data encoded with the same key must result in the same token"); - } - - [TestMethod] - public void Encode_Should_Return_Token_With_Custom_Extra_Headers_Full_Payload_And_Claims_With_Nested() - { - const string key = TestData.Secret; - - var token = JwtBuilder.Create() - .WithAlgorithm(TestData.HMACSHA256Algorithm) - .WithSecret(key) - .AddHeader("version", 1) - .AddClaim("ExtraClaim", new { NestedProperty1 = "Foo", NestedProperty2 = 3 }) - .Encode(TestData.Customer); - - token.Should() - .Be(TestData.TokenWithCustomTypeHeader3AndClaimNested, "because the same data encoded with the same key must result in the same token"); - } - - [TestMethod] - public void Encode_Should_Return_Token_With_Custom_Extra_Headers_Full_Payload_And_Claims_With_Nested_TypesMatch() - { - const string key = TestData.Secret; - - var token = JwtBuilder.Create() - .WithAlgorithm(TestData.HMACSHA256Algorithm) - .WithSecret(key) - .AddHeader("version", 1) - .AddClaim("ExtraClaim", new { NestedProperty1 = "Foo", NestedProperty2 = 3 }) - .Encode(typeof(Customer), TestData.Customer); + Action action = () => + JwtBuilder.Create() + .WithAlgorithm(TestData.HMACSHA256Algorithm) + .WithSecret(key) + .AddHeader("version", 1) + .AddClaim("ExtraClaim", "ValueClaim") + .Encode(TestData.Customer); - token.Should() - .Be(TestData.TokenWithCustomTypeHeader3AndClaimNested, "because the same data encoded with the same key must result in the same token"); + action.Should() + .Throw("because using both Encode(payload) and AddClaim is not supported"); } [TestMethod] - public void Encode_Should_Return_ThrowTargetException_Encode_TypesMatch() + public void Encode_Should_Throw_NotSupportedException_When_Using_EncodePayload_WithAddClaims() { const string key = TestData.Secret; Action action = () => + { + var claims = new Dictionary + { + {"Key" , "Value"} + }; + JwtBuilder.Create() - .WithAlgorithm(TestData.HMACSHA256Algorithm) - .WithSecret(key) - .AddHeader("version", 1) - .AddClaim("ExtraClaim", new { NestedProperty1 = "Foo", NestedProperty2 = 3 }) - .Encode(typeof(string), TestData.Customer); + .WithAlgorithm(TestData.HMACSHA256Algorithm) + .WithSecret(key) + .AddHeader("version", 1) + .AddClaims(claims) + .Encode(TestData.Customer); + }; - if (IsRunningOnMono()) - { - action.Should() - .Throw("Exception has been thrown by the target of an invocation."); - } - else - { - action.Should() - .Throw("Object does not match target type."); - } + action.Should() + .Throw("because using both Encode(payload) and AddClaims is not supported"); } - + /// /// Copied from: https://stackoverflow.com/a/7077620/2890855 /// From ff860a599acf4d137322d7a4f82c7b54529a3a32 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:14:59 -0800 Subject: [PATCH 19/27] Update JwtBuilder.cs --- src/JWT/Builder/JwtBuilder.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 7008eaa3d..f14adb965 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -278,8 +278,7 @@ public string Encode(object payload) if (_jwt.Payload.Any()) { - throw new NotSupportedException( - "Having JWT as a key-value store and implicit payload is not supported."); + throw new NotSupportedException("Supplying both key-value pairs and implicit payload is not supported."); } return _encoder.Encode(_jwt.Header, payload, _secrets?[0]); From 979e1598bc4b735daefd663272b6e1e44b6b742f Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:15:53 -0800 Subject: [PATCH 20/27] Update JwtBuilderEncodeTests.cs --- .../Builder/JwtBuilderEncodeTests.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs index 7a3787943..1245e9261 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs @@ -236,14 +236,14 @@ public void Encode_Should_Throw_NotSupportedException_When_Using_EncodePayload_W Action action = () => JwtBuilder.Create() - .WithAlgorithm(TestData.HMACSHA256Algorithm) - .WithSecret(key) - .AddHeader("version", 1) - .AddClaim("ExtraClaim", "ValueClaim") - .Encode(TestData.Customer); + .WithAlgorithm(TestData.HMACSHA256Algorithm) + .WithSecret(key) + .AddHeader("version", 1) + .AddClaim("ExtraClaim", "ValueClaim") + .Encode(TestData.Customer); action.Should() - .Throw("because using both Encode(payload) and AddClaim is not supported"); + .Throw("because using both Encode(payload) and AddClaim is not supported"); } [TestMethod] @@ -255,19 +255,19 @@ public void Encode_Should_Throw_NotSupportedException_When_Using_EncodePayload_W { var claims = new Dictionary { - {"Key" , "Value"} + { "key" , "value" } }; JwtBuilder.Create() - .WithAlgorithm(TestData.HMACSHA256Algorithm) - .WithSecret(key) - .AddHeader("version", 1) - .AddClaims(claims) - .Encode(TestData.Customer); + .WithAlgorithm(TestData.HMACSHA256Algorithm) + .WithSecret(key) + .AddHeader("version", 1) + .AddClaims(claims) + .Encode(TestData.Customer); }; action.Should() - .Throw("because using both Encode(payload) and AddClaims is not supported"); + .Throw("because using both Encode(payload) and AddClaims() is not supported"); } /// From e48515bd260a2b9549a81d19ad93a1cc7d78fa19 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:16:12 -0800 Subject: [PATCH 21/27] Update JwtBuilderEncodeTests.cs --- .../Builder/JwtBuilderEncodeTests.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs index 1245e9261..e26a3d804 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs @@ -236,11 +236,11 @@ public void Encode_Should_Throw_NotSupportedException_When_Using_EncodePayload_W Action action = () => JwtBuilder.Create() - .WithAlgorithm(TestData.HMACSHA256Algorithm) - .WithSecret(key) - .AddHeader("version", 1) - .AddClaim("ExtraClaim", "ValueClaim") - .Encode(TestData.Customer); + .WithAlgorithm(TestData.HMACSHA256Algorithm) + .WithSecret(key) + .AddHeader("version", 1) + .AddClaim("ExtraClaim", "ValueClaim") + .Encode(TestData.Customer); action.Should() .Throw("because using both Encode(payload) and AddClaim is not supported"); @@ -259,11 +259,11 @@ public void Encode_Should_Throw_NotSupportedException_When_Using_EncodePayload_W }; JwtBuilder.Create() - .WithAlgorithm(TestData.HMACSHA256Algorithm) - .WithSecret(key) - .AddHeader("version", 1) - .AddClaims(claims) - .Encode(TestData.Customer); + .WithAlgorithm(TestData.HMACSHA256Algorithm) + .WithSecret(key) + .AddHeader("version", 1) + .AddClaims(claims) + .Encode(TestData.Customer); }; action.Should() From 1f3e8d984bee47d0492279dbfce672771a4efba6 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:17:21 -0800 Subject: [PATCH 22/27] Update JwtBuilderDecodeTests.cs --- .../JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index c63400822..54f9eae1a 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -472,17 +472,16 @@ public void Encode_Decode_Should_Return_Token_Nested_Data_ShouldRespectAttribute }; var encoded = JwtBuilder.Create() - .WithAlgorithm(alg) - .WithJsonSerializer(serializer) - .AddClaim("Data", expected) - .Encode(); + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .AddClaim("Data", expected) + .Encode(); encoded.Should().NotBeNullOrEmpty(); Console.WriteLine(encoded); var jwtBuilder = JwtBuilder.Create() .WithAlgorithm(alg) - .WithJsonSerializer(serializer) - .WithJsonSerializer(serializer); + .WithJsonSerializer(serializer); var payloadType = new TestData.PayloadWithNestedJsonNetData { From ab55426f1f38d016147cd846035b81341f2b6848 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:17:44 -0800 Subject: [PATCH 23/27] Update JwtBuilderDecodeTests.cs --- .../JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index 54f9eae1a..cc88ba68a 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -472,10 +472,10 @@ public void Encode_Decode_Should_Return_Token_Nested_Data_ShouldRespectAttribute }; var encoded = JwtBuilder.Create() - .WithAlgorithm(alg) - .WithJsonSerializer(serializer) - .AddClaim("Data", expected) - .Encode(); + .WithAlgorithm(alg) + .WithJsonSerializer(serializer) + .AddClaim("Data", expected) + .Encode(); encoded.Should().NotBeNullOrEmpty(); Console.WriteLine(encoded); @@ -507,7 +507,7 @@ public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecorate var encoded = JwtBuilder.Create() .WithAlgorithm(alg) .WithJsonSerializer(serializer) - .Encode(expected); + .Encode(expected); encoded.Should().NotBeNullOrEmpty(); var actual = JwtBuilder.Create() From 4d6c349bee63849a1fae046bddcee8e40fe57d30 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:18:14 -0800 Subject: [PATCH 24/27] Update JWT.csproj --- src/JWT/JWT.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JWT/JWT.csproj b/src/JWT/JWT.csproj index bfb845adc..579726def 100644 --- a/src/JWT/JWT.csproj +++ b/src/JWT/JWT.csproj @@ -20,7 +20,7 @@ Alexander Batishchev, John Sheehan, Michael Lehenbauer jwt;json;authorization CC0-1.0 - 10.0.2-beta1 + 10.0.2 10.0.0.0 10.0.0.0 JWT From ba6f381f51210c7d50d926b509a8a1af38acf4cc Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:30:04 -0800 Subject: [PATCH 25/27] Update JWT.Extensions.AspNetCore.csproj --- src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj b/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj index 52a7567d2..be0218711 100644 --- a/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj +++ b/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj @@ -10,7 +10,7 @@ Alexander Batishchev jwt;json;asp.net;asp.net core;.net core;authorization MIT - 10.1.0 + 10.1.1 10.0.0.0 10.0.0.0 JWT.Extensions.AspNetCore From 32b08b923219ed559f8bcc8d2f4a14aa5cffa381 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:30:17 -0800 Subject: [PATCH 26/27] Update JWT.Extensions.DependencyInjection.csproj --- .../JWT.Extensions.DependencyInjection.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JWT.Extensions.DependencyInjection/JWT.Extensions.DependencyInjection.csproj b/src/JWT.Extensions.DependencyInjection/JWT.Extensions.DependencyInjection.csproj index eb63076bc..aed93e459 100644 --- a/src/JWT.Extensions.DependencyInjection/JWT.Extensions.DependencyInjection.csproj +++ b/src/JWT.Extensions.DependencyInjection/JWT.Extensions.DependencyInjection.csproj @@ -11,7 +11,7 @@ Alexander Batishchev jwt;json;asp.net;asp.net core;.net core;authorization;dependenсy injection MIT - 2.2.2 + 2.2.3 2.0.0.0 2.0.0.0 JWT From 7920a172425b5970aa5dbf8ad1e8660e4c4731f1 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 31 Jan 2023 15:31:35 -0800 Subject: [PATCH 27/27] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f9f664c9..ef50060eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ - TBD +# 10.0.2 + +- Disallowed Encode(payload) with AddClaim(s) + # 10.0.1 - Fixed deserializing JWT header