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
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
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
diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs
index 36f6c61f4..f14adb965 100644
--- a/src/JWT/Builder/JwtBuilder.cs
+++ b/src/JWT/Builder/JwtBuilder.cs
@@ -1,8 +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
@@ -263,27 +269,19 @@ 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 => prop.Name, 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("Supplying both key-value pairs and implicit payload is not supported.");
}
- return Encode();
+ return _encoder.Encode(_jwt.Header, payload, _secrets?[0]);
}
///
@@ -320,6 +318,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.
///
@@ -468,5 +474,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/JWT.csproj b/src/JWT/JWT.csproj
index 7513c1e4a..579726def 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.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..cc88ba68a 100644
--- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs
+++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs
@@ -433,5 +433,115 @@ public void Decode_ToDictionary_Without_Serializer_Should_Throw_Exception()
action.Should()
.Throw();
}
+
+ [TestMethod]
+ public void Encode_Decode_ToJsonNetDecoratedType_Should_UseDecoratedName_Bug456()
+ {
+ var serializer = new JsonNetSerializer();
+ var alg = new NoneAlgorithm();
+
+ var token = JwtBuilder.Create()
+ .WithAlgorithm(alg)
+ .WithJsonSerializer(serializer);
+
+ var expected = new TestData.TestDataJsonNetDecorated
+ {
+ City = "Amsterdam",
+ };
+
+ var encoded = token.Encode(expected);
+ encoded.Should().NotBeNullOrEmpty();
+
+ token = JwtBuilder.Create()
+ .WithAlgorithm(alg)
+ .WithJsonSerializer(serializer);
+
+ var actual = token.Decode(encoded);
+ 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);
+
+ 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_OR_GREATER
+ [TestMethod]
+ public void Encode_Decode_ToSystemTextSerializerDecoratedType_Should_UseDecoratedName_Bug456()
+ {
+ var serializer = new SystemTextSerializer();
+ var alg = new NoneAlgorithm();
+
+ var expected = new TestData.TestDataSystemTextSerializerDecorated
+ {
+ City = "Amsterdam",
+ };
+
+ var encoded = JwtBuilder.Create()
+ .WithAlgorithm(alg)
+ .WithJsonSerializer(serializer)
+ .Encode(expected);
+ encoded.Should().NotBeNullOrEmpty();
+
+ var actual = JwtBuilder.Create()
+ .WithAlgorithm(alg)
+ .WithJsonSerializer(serializer)
+ .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();
+
+ var actual = JwtBuilder.Create()
+ .WithAlgorithm(alg)
+ .WithJsonSerializer(serializer)
+ .WithJsonSerializer(serializer)
+ .Decode(encoded);
+ actual.Data.Should().BeEquivalentTo(expected);
+ }
+#endif
}
}
diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderEncodeTests.cs
index 2dd229f23..e26a3d804 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);
+ .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
///
@@ -382,6 +350,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()
{
diff --git a/tests/JWT.Tests.Common/Models/TestData.cs b/tests/JWT.Tests.Common/Models/TestData.cs
index 94da079e8..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
@@ -17,6 +17,30 @@ public static class TestData
Age = 33
};
+ public class PayloadWithNestedJsonNetData
+ {
+ public TestDataJsonNetDecorated Data { get; set; }
+ }
+
+ public class TestDataJsonNetDecorated
+ {
+ [Newtonsoft.Json.JsonProperty("AT")]
+ public string City { get; set; }
+ }
+
+#if NETSTANDARD2_0 || NET6_0
+ public class PayloadWithNestedSystemTextSerializerData
+ {
+ public TestDataSystemTextSerializerDecorated Data { get; set; }
+ }
+
+ public class TestDataSystemTextSerializerDecorated
+ {
+ [System.Text.Json.Serialization.JsonPropertyName("AT")]
+ public string City { get; set; }
+ }
+#endif
+
public const string Secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
public const string Secret2 = "QWORIJkmQWEDIHbjhOIHAUSDFOYnUGWEYT";
@@ -68,7 +92,7 @@ public static class TestData
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()
@@ -83,4 +107,4 @@ private static X509Certificate2 CreateCertificate()
}
#endif
}
-}
\ No newline at end of file
+}