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

Fixed deserializing JWT header #459

Merged
merged 5 commits into from
Jan 18, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
32 changes: 19 additions & 13 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions JWT.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion JWT.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_MEMBERS/@EntryValue">Property</s:String>
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderText/@EntryValue"></s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HMACSHA/@EntryIndexedValue">HMACSHA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RS/@EntryIndexedValue">RS</s:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Authors>Alexander Batishchev</Authors>
<PackageTags>jwt;json;asp.net;asp.net core;.net core;authorization</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Version>10.0.0</Version>
<Version>10.0.1</Version>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<RootNamespace>JWT.Extensions.AspNetCore</RootNamespace>
Expand All @@ -30,8 +30,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Condition="$(DefineConstants.Contains(MODERN_DOTNET))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Text.Json" Version="6.0.7" Condition="$(DefineConstants.Contains(MODERN_DOTNET))" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Authors>Alexander Batishchev</Authors>
<PackageTags>jwt;json;asp.net;asp.net core;.net core;authorization;dependenсy injection</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Version>2.2.0</Version>
<Version>2.2.1</Version>
<FileVersion>2.0.0.0</FileVersion>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<RootNamespace>JWT</RootNamespace>
Expand All @@ -30,8 +30,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.25" />
<PackageReference Condition="$(DefineConstants.Contains(MODERN_DOTNET))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Condition="$(DefineConstants.Contains(MODERN_DOTNET))" Include="System.Text.Json" Version="6.0.7" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/JWT/Builder/JwtData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public JwtData()
/// <summary>
/// Creates a new instance of <see cref="JwtData" />
/// </summary>
/// <param name="payload">Dictionary that contans the payload</param>
/// <param name="payload">Dictionary that contains the payload</param>
public JwtData(IDictionary<string, object> payload)
: this(null, payload)
{
Expand All @@ -31,7 +31,7 @@ public JwtData(IDictionary<string, object> payload)
/// Creates a new instance of <see cref="JwtData" />
/// </summary>
/// <param name="header">Dictionary that contains the headers</param>
/// <param name="payload">Dictionary that contans the payload</param>
/// <param name="payload">Dictionary that contains the payload</param>
public JwtData(IDictionary<string, object> header, IDictionary<string, object> payload)
{
this.Header = header ?? new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
Expand Down
27 changes: 24 additions & 3 deletions src/JWT/Builder/JwtHeader.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
Expand All @@ -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; }
}
}
8 changes: 4 additions & 4 deletions src/JWT/JWT.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0;net6.0;net35;net40;net462;</TargetFrameworks>
Expand All @@ -20,7 +20,7 @@
<Authors>Alexander Batishchev, John Sheehan, Michael Lehenbauer</Authors>
<PackageTags>jwt;json;authorization</PackageTags>
<PackageLicenseExpression>CC0-1.0</PackageLicenseExpression>
<Version>10.0.0</Version>
<Version>10.0.1</Version>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<RootNamespace>JWT</RootNamespace>
Expand All @@ -38,8 +38,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Condition="$(DefineConstants.Contains(MODERN_DOTNET))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Condition="$(DefineConstants.Contains(MODERN_DOTNET))" Include="System.Text.Json" Version="6.0.7" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3' OR '$(TargetFramework)' == 'netstandard2.0'">
Expand Down
9 changes: 8 additions & 1 deletion src/JWT/JwtDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,18 @@ private static bool AllKeysHaveValues(byte[][] keys)
private void ValidateNoneAlgorithm(JwtParts jwt)
{
var header = DecodeHeader<JwtHeader>(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))
{
throw new InvalidOperationException("Signature is not acceptable for algorithm None");
}
}
}
}
}
2 changes: 1 addition & 1 deletion tests/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.1.25" Condition="'$(TargetFramework)' == 'netcoreapp3.1'" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.5" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="System.Text.Json" Version="6.0.4" />
<PackageReference Include="System.Text.Json" Version="6.0.7" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
</ItemGroup>

<ItemGroup>
Expand Down
31 changes: 27 additions & 4 deletions tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using FluentAssertions;
using JWT.Algorithms;
using JWT.Builder;
using JWT.Serializers;
using JWT.Tests.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;

Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -118,9 +119,31 @@ public void Decode_With_MustVerifySignature_Should_Not_Be_Allowed_For_For_None_A
action.Should()
.Throw<InvalidOperationException>("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<Customer>(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())
Expand Down