Skip to content

Commit

Permalink
Disallow Encode(payload) with AddClaim(s) (#464)
Browse files Browse the repository at this point in the history
* Disallowed Encode(payload) with AddClaim(s)
* Updated tests
* Bumped JWT version to 10.0.2
* Bumped JWT.Extensions.DependencyInjection version to 2.2.3
* Bumped JWT.Extensions.AspNetCore version to 10.1.1

---------

Co-authored-by: Alexander Batishchev <[email protected]>
Co-authored-by: Markus Hartung <[email protected]>
  • Loading branch information
3 people authored Jan 31, 2023
1 parent 79ac65b commit 9cd3ed8
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 76 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

- TBD

# 10.0.2

- Disallowed Encode(payload) with AddClaim(s)

# 10.0.1

- Fixed deserializing JWT header
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<Authors>Alexander Batishchev</Authors>
<PackageTags>jwt;json;asp.net;asp.net core;.net core;authorization</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Version>10.1.0</Version>
<Version>10.1.1</Version>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<RootNamespace>JWT.Extensions.AspNetCore</RootNamespace>
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.2</Version>
<Version>2.2.3</Version>
<FileVersion>2.0.0.0</FileVersion>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<RootNamespace>JWT</RootNamespace>
Expand Down
71 changes: 57 additions & 14 deletions src/JWT/Builder/JwtBuilder.cs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -263,27 +269,19 @@ public string Encode()
return _encoder.Encode(_jwt.Header, _jwt.Payload, _secrets?[0]);
}

public string Encode<T>(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]);
}

/// <summary>
Expand Down Expand Up @@ -320,6 +318,14 @@ public T DecodeHeader<T>(string token)
return _decoder.DecodeHeader<T>(token);
}

public object Decode(string token, Type type)
{
EnsureCanDecode();

return _decoder.DecodeToObject(type, token, _secrets, _valParams.ValidateSignature);
}


/// <summary>
/// Decodes a token using the supplied dependencies.
/// </summary>
Expand Down Expand Up @@ -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;
}
}
}
4 changes: 2 additions & 2 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.1</Version>
<Version>10.0.2</Version>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<RootNamespace>JWT</RootNamespace>
Expand Down
110 changes: 110 additions & 0 deletions tests/JWT.Tests.Common/Builder/JwtBuilderDecodeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,5 +433,115 @@ public void Decode_ToDictionary_Without_Serializer_Should_Throw_Exception()
action.Should()
.Throw<ArgumentNullException>();
}

[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<TestData.TestDataJsonNetDecorated>(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<TestData.TestDataJsonNetDecorated>("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<TestData.TestDataSystemTextSerializerDecorated>(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<TestData.TestDataSystemTextSerializerDecorated>("Data", expected)
.Encode();
encoded.Should().NotBeNullOrEmpty();

var actual = JwtBuilder.Create()
.WithAlgorithm(alg)
.WithJsonSerializer(serializer)
.WithJsonSerializer(serializer)
.Decode<TestData.PayloadWithNestedSystemTextSerializerData>(encoded);
actual.Data.Should().BeEquivalentTo(expected);
}
#endif
}
}
Loading

0 comments on commit 9cd3ed8

Please sign in to comment.