From ebc094504913d8ba883ab07e8d54ef6c67b69984 Mon Sep 17 00:00:00 2001 From: Alexander Batishchev Date: Tue, 17 Jan 2023 19:09:55 -0800 Subject: [PATCH] Fixed deserializing JWT header (#459) * Fixed deserializing JWT header * Updated Newtonsoft.Json to version to 13.0.2 * Updated System.Text.Json to version 6.0.7 * Updated Microsoft.NET.Test.Sdk to version 17.4.1 * Bumped version of JWT to 10.0.1 * Bumped version of JWT.Extensions.AspNetCore to 10.0.01 * Bumped version of JWT.Extensions.DependencyInjection to 2.2.1 --- .editorconfig | 11 +++++++ CHANGELOG.md | 32 +++++++++++-------- JWT.sln | 1 + JWT.sln.DotSettings | 1 - .../JWT.Extensions.AspNetCore.csproj | 6 ++-- .../JWT.Extensions.DependencyInjection.csproj | 6 ++-- src/JWT/Builder/JwtData.cs | 4 +-- src/JWT/Builder/JwtHeader.cs | 27 ++++++++++++++-- src/JWT/JWT.csproj | 8 ++--- src/JWT/JwtDecoder.cs | 9 +++++- tests/Directory.Build.props | 2 +- .../JWT.Extensions.AspNetCore.Tests.csproj | 5 +-- ...xtensions.DependencyInjection.Tests.csproj | 3 -- .../Builder/JwtBuilderDecodeTests.cs | 31 +++++++++++++++--- 14 files changed, 104 insertions(+), 42 deletions(-) diff --git a/.editorconfig b/.editorconfig index 813e33e34..e4ec90243 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,3 +8,14 @@ indent_style = space; indent_size = 4; insert_final_newline = false; trim_trailing_whitespace = true; + +## IDE + +# IDE0003: Remove qualification +dotnet_style_qualification_for_property = true:warning + +# IDE0049: Simplify Names +dotnet_style_predefined_type_for_member_access = false + +# IDE0090: Use 'new(...)' +csharp_style_implicit_object_creation_when_type_is_apparent = false \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 21e1a0c3c..3f9f664c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,19 @@ -# Unreleased - -- TBD - -# 10.0.0 - -- Made NoneAlgorithm not requiring any keys as it is not signed -- Added option to select default serializer, Newtonsoft.Json or System.Text.Json (#433) -- Renamed default IdentityFactory in Jwt.Extensions.AspNetCore, opened up for inheritance, extension (#428) -- Added Encode(T) and Encode(Type, object) to JwtBuilder (#415) -- Bumped Newtonsoft.Json from 10.0.3 to 13.0.1 -- Fixed typos in exception messages -- Made verify=true by default in IJwtDecoder methods +# Unreleased + +- TBD + +# 10.0.1 + +- Fixed deserializing JWT header +- Updated Newtonsoft.Json to version to 13.0.2 +- Updated System.Text.Json to version 6.0.7 + +# 10.0.0 + +- Made NoneAlgorithm not requiring any keys as it is not signed +- Added option to select default serializer, Newtonsoft.Json or System.Text.Json (#433) +- Renamed default IdentityFactory in Jwt.Extensions.AspNetCore, opened up for inheritance, extension (#428) +- Added Encode(T) and Encode(Type, object) to JwtBuilder (#415) +- Updated Newtonsoft.Json to version 13.0.1 +- Fixed typos in exception messages +- Made verify=true by default in IJwtDecoder methods diff --git a/JWT.sln b/JWT.sln index 70349a870..cdf76a388 100644 --- a/JWT.sln +++ b/JWT.sln @@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_", "_", "{513CE2B5-E0D6-43 ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig .gitignore = .gitignore + CHANGELOG.md = CHANGELOG.md Directory.Build.props = Directory.Build.props JWT.sln.DotSettings = JWT.sln.DotSettings JwtStrongNameKey.snk = JwtStrongNameKey.snk diff --git a/JWT.sln.DotSettings b/JWT.sln.DotSettings index b2b4dda35..1d78e6624 100644 --- a/JWT.sln.DotSettings +++ b/JWT.sln.DotSettings @@ -1,5 +1,4 @@  - Property HMACSHA RS diff --git a/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj b/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj index cc5e95128..70160da8d 100644 --- a/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj +++ b/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj @@ -11,7 +11,7 @@ Alexander Batishchev jwt;json;asp.net;asp.net core;.net core;authorization MIT - 10.0.0 + 10.0.1 10.0.0.0 10.0.0.0 JWT.Extensions.AspNetCore @@ -30,8 +30,8 @@ - - + + diff --git a/src/JWT.Extensions.DependencyInjection/JWT.Extensions.DependencyInjection.csproj b/src/JWT.Extensions.DependencyInjection/JWT.Extensions.DependencyInjection.csproj index ff1d976d8..3918cfa2d 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.0 + 2.2.1 2.0.0.0 2.0.0.0 JWT @@ -30,8 +30,8 @@ - - + + diff --git a/src/JWT/Builder/JwtData.cs b/src/JWT/Builder/JwtData.cs index 35086c7fe..5f61b599d 100644 --- a/src/JWT/Builder/JwtData.cs +++ b/src/JWT/Builder/JwtData.cs @@ -21,7 +21,7 @@ public JwtData() /// /// Creates a new instance of /// - /// Dictionary that contans the payload + /// Dictionary that contains the payload public JwtData(IDictionary payload) : this(null, payload) { @@ -31,7 +31,7 @@ public JwtData(IDictionary payload) /// Creates a new instance of /// /// Dictionary that contains the headers - /// Dictionary that contans the payload + /// Dictionary that contains the payload public JwtData(IDictionary header, IDictionary payload) { this.Header = header ?? new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/src/JWT/Builder/JwtHeader.cs b/src/JWT/Builder/JwtHeader.cs index 08ad1ba72..0d67df5f7 100644 --- a/src/JWT/Builder/JwtHeader.cs +++ b/src/JWT/Builder/JwtHeader.cs @@ -1,9 +1,9 @@ #if MODERN_DOTNET -using JsonProperty = System.Text.Json.Serialization.JsonPropertyNameAttribute; -#else -using Newtonsoft.Json; +using System.Text.Json.Serialization; #endif +using Newtonsoft.Json; + namespace JWT.Builder { /// @@ -12,24 +12,45 @@ namespace JWT.Builder public class JwtHeader { [JsonProperty("typ")] +#if MODERN_DOTNET + [JsonPropertyName("typ")] +#endif public string Type { get; set; } [JsonProperty("cty")] +#if MODERN_DOTNET + [JsonPropertyName("cty")] +#endif public string ContentType { get; set; } [JsonProperty("alg")] +#if MODERN_DOTNET + [JsonPropertyName("alg")] +#endif public string Algorithm { get; set; } [JsonProperty("kid")] +#if MODERN_DOTNET + [JsonPropertyName("kid")] +#endif public string KeyId { get; set; } [JsonProperty("x5u")] +#if MODERN_DOTNET + [JsonPropertyName("x5u")] +#endif public string X5u { get; set; } [JsonProperty("x5c")] +#if MODERN_DOTNET + [JsonPropertyName("x5c")] +#endif public string[] X5c { get; set; } [JsonProperty("x5t")] +#if MODERN_DOTNET + [JsonPropertyName("x5t")] +#endif public string X5t { get; set; } } } \ No newline at end of file diff --git a/src/JWT/JWT.csproj b/src/JWT/JWT.csproj index c43c70904..7513c1e4a 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.0 + 10.0.1 10.0.0.0 10.0.0.0 JWT @@ -38,8 +38,8 @@ - - + + diff --git a/src/JWT/JwtDecoder.cs b/src/JWT/JwtDecoder.cs index 7d58bfe96..d9368b0f4 100644 --- a/src/JWT/JwtDecoder.cs +++ b/src/JWT/JwtDecoder.cs @@ -294,6 +294,13 @@ private static bool AllKeysHaveValues(byte[][] keys) private void ValidateNoneAlgorithm(JwtParts jwt) { var header = DecodeHeader(jwt); + + if (String.IsNullOrEmpty(header.Type) && + String.IsNullOrEmpty(header.Algorithm)) + { + throw new InvalidOperationException("Error deserializing JWT header, all mandatory properties are null or empty"); + } + if (String.Equals(header.Algorithm, nameof(JwtAlgorithmName.None), StringComparison.OrdinalIgnoreCase) && !String.IsNullOrEmpty(jwt.Signature)) { @@ -301,4 +308,4 @@ private void ValidateNoneAlgorithm(JwtParts jwt) } } } -} +} \ No newline at end of file diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index bb6032bc6..68806dc90 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -32,7 +32,7 @@ - + diff --git a/tests/JWT.Extensions.AspNetCore.Tests/JWT.Extensions.AspNetCore.Tests.csproj b/tests/JWT.Extensions.AspNetCore.Tests/JWT.Extensions.AspNetCore.Tests.csproj index 79d851dd1..4f65eaf3d 100644 --- a/tests/JWT.Extensions.AspNetCore.Tests/JWT.Extensions.AspNetCore.Tests.csproj +++ b/tests/JWT.Extensions.AspNetCore.Tests/JWT.Extensions.AspNetCore.Tests.csproj @@ -8,10 +8,7 @@ - - - - + diff --git a/tests/JWT.Extensions.DependencyInjection.Tests/JWT.Extensions.DependencyInjection.Tests.csproj b/tests/JWT.Extensions.DependencyInjection.Tests/JWT.Extensions.DependencyInjection.Tests.csproj index 59103ab3d..e372811a6 100644 --- a/tests/JWT.Extensions.DependencyInjection.Tests/JWT.Extensions.DependencyInjection.Tests.csproj +++ b/tests/JWT.Extensions.DependencyInjection.Tests/JWT.Extensions.DependencyInjection.Tests.csproj @@ -6,9 +6,6 @@ - - - diff --git a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs index 911be2ffc..dbafb02cf 100644 --- a/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs +++ b/tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs @@ -3,6 +3,7 @@ using FluentAssertions; using JWT.Algorithms; using JWT.Builder; +using JWT.Serializers; using JWT.Tests.Models; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -82,7 +83,7 @@ public void Decode_Using_Asymmetric_Algorithm_Should_Return_Token() } [TestMethod] - public void Decode_Using_Signature_Is_Not_Accepted_For_None_Algorithm() + public void Decode_Using_Signature_For_None_Algorithm_Should_Throw_Exception() { Action action = () => JwtBuilder.Create() @@ -107,7 +108,7 @@ public void Decode_Using_Empty_Signature_Should_Work_For_None_Algorithm() } [TestMethod] - public void Decode_With_MustVerifySignature_Should_Not_Be_Allowed_For_For_None_Algorithm() + public void Decode_With_MustVerifySignature_For_None_Algorithm_Should_Throw_Exception() { Action action = () => JwtBuilder.Create() @@ -118,9 +119,31 @@ public void Decode_With_MustVerifySignature_Should_Not_Be_Allowed_For_For_None_A action.Should() .Throw("verify signature is not supported for none algorithm"); } - + + [TestMethod] + public void Decode_Should_Return_Token_For_None_Algorithm() + { + var token = JwtBuilder.Create() + .WithAlgorithm(new NoneAlgorithm()) + .WithSecret(TestData.Secret) + .WithJsonSerializer(new JsonNetSerializer()); + + var encodedModel = token.Encode(TestData.Customer); + encodedModel.Should() + .NotBeNullOrEmpty(); + + token = JwtBuilder.Create() + .WithAlgorithm(new NoneAlgorithm()) + .WithSecret(TestData.Secret) + .WithJsonSerializer(new JsonNetSerializer()); + + var decodedModel = token.Decode(encodedModel); + decodedModel.Should() + .NotBeNull(); + } + [TestMethod] - public void Decode_Using_No_Secret_Should_Work_For_None_Algorithm() + public void Decode_With_No_Secret_Should_Return_Token_For_None_Algorithm() { var token = JwtBuilder.Create() .WithAlgorithm(new NoneAlgorithm())