Skip to content

Commit

Permalink
Adds JsonWebToken Constructor that accepts Memory<char> (#2458)
Browse files Browse the repository at this point in the history
* Add JWT ctor that accepts a span

* Update YAML to build previews

* Add ReadOnlySpan overloads

* Add benchmark

* Add ValidateAndGetOutputSize for spans

* Remove duplication

* Update benchmark

* Remove duplicates

* Update

* Add benchmarks

* Update

* Replace ReadyOnlySpan with ReadOnlyMemory

* Update test

* Update benchmark naming

* Move ArrayPool to JsonWebToken level

* Update CreateHeaderClaimSet

* Update benchmark for JWE to resolve error

* Reduce duplication

* Fix comment

* Set _encodedTokenMemory as readonly

* Remove unnecessary private method

* Use Base64UrlEncoding.Decode with action

* Use ValidateAndGetOutputSize(ReadOnlySpan<char> strSpan..) thoughout

* Add tests

* Revert change

* Temporarily allow publishing to NuGet

* use just `1` for preview

* up version to 7.4.0 for preview

* Separate JWS and JWE benchmarks

* Re-add variable

* Update test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenTests.cs

Co-authored-by: Peter <[email protected]>

* Update src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs

Co-authored-by: Peter <[email protected]>

* Update test/Microsoft.IdentityModel.Tokens.Tests/Base64UrlEncodingTests.cs

Co-authored-by: Peter <[email protected]>

* Removed private method

* Store ReadOnlySpan is a variable

* Update benchmark

* Cleanup

* Fix CreateHeaderClaimSet and CreatePayloadClaimSet to avoid reading the end of the span

* Add comment

* Update benchmark

---------

Co-authored-by: Sruthi Keerthi Rangavajhula <[email protected]>
Co-authored-by: jennyf19 <[email protected]>
Co-authored-by: Peter <[email protected]>
  • Loading branch information
4 people authored Feb 25, 2024
1 parent d28f795 commit d5dc77e
Show file tree
Hide file tree
Showing 13 changed files with 374 additions and 132 deletions.
4 changes: 4 additions & 0 deletions benchmark/Microsoft.IdentityModel.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public static void Main(string[] args)
}
private static void DebugThroughTests()
{
ReadJWETokenTests readTokenTests = new ReadJWETokenTests();
readTokenTests.Setup();
readTokenTests.ReadJWE_FromMemory();

AsymmetricAdapterSignatures asymmetricAdapter = new AsymmetricAdapterSignatures();
asymmetricAdapter.Setup();
asymmetricAdapter.SignDotnetCreatingBufferRSA();
Expand Down
46 changes: 46 additions & 0 deletions benchmark/Microsoft.IdentityModel.Benchmarks/ReadJWETokenTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using BenchmarkDotNet.Attributes;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;

namespace Microsoft.IdentityModel.Benchmarks
{
// dotnet run -c release -f net8.0 --filter Microsoft.IdentityModel.Benchmarks.ReadTokenTests*

public class ReadJWETokenTests
{
string _encryptedJWE;
ReadOnlyMemory<char> _encryptedJWEAsMemory;

[GlobalSetup]
public void Setup()
{
var jsonWebTokenHandler = new JsonWebTokenHandler();
var jweTokenDescriptor = new SecurityTokenDescriptor
{
SigningCredentials = BenchmarkUtils.SigningCredentialsRsaSha256,
EncryptingCredentials = BenchmarkUtils.EncryptingCredentialsAes256Sha512,
TokenType = JwtHeaderParameterNames.Jwk,
Claims = BenchmarkUtils.Claims
};

_encryptedJWE = jsonWebTokenHandler.CreateToken(jweTokenDescriptor);
_encryptedJWEAsMemory = _encryptedJWE.AsMemory();
}

[Benchmark]
public JsonWebToken ReadJWE_FromString()
{
return new JsonWebToken(_encryptedJWE);
}

[Benchmark]
public JsonWebToken ReadJWE_FromMemory()
{
return new JsonWebToken(_encryptedJWEAsMemory);
}
}
}
45 changes: 45 additions & 0 deletions benchmark/Microsoft.IdentityModel.Benchmarks/ReadJWSTokenTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using BenchmarkDotNet.Attributes;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;

namespace Microsoft.IdentityModel.Benchmarks
{
// dotnet run -c release -f net8.0 --filter Microsoft.IdentityModel.Benchmarks.ReadJWSTokenTests*

public class ReadJWSTokenTests
{
string _encodedJWS;
ReadOnlyMemory<char> _encodedJWSAsMemory;

[GlobalSetup]
public void Setup()
{
var jsonWebTokenHandler = new JsonWebTokenHandler();
var jwsTokenDescriptor = new SecurityTokenDescriptor
{
SigningCredentials = BenchmarkUtils.SigningCredentialsRsaSha256,
TokenType = JwtHeaderParameterNames.Jwk,
Claims = BenchmarkUtils.Claims
};

_encodedJWS = jsonWebTokenHandler.CreateToken(jwsTokenDescriptor);
_encodedJWSAsMemory = _encodedJWS.AsMemory();
}

[Benchmark]
public JsonWebToken ReadJWS_FromString()
{
return new JsonWebToken(_encodedJWS);
}

[Benchmark]
public JsonWebToken ReadJWS_FromMemory()
{
return new JsonWebToken(_encodedJWSAsMemory);
}
}
}
9 changes: 9 additions & 0 deletions build/releaseBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,15 @@ jobs:
BuildDropPath: '$(Build.SourcesDirectory)\src'
ManifestDirPath: '$(Build.SourcesDirectory)\artifacts'

- task: NuGetCommand@2
displayName: 'Upload NuGet Package to VSTS NuGet'
condition: eq(variables['NugetPackageType'], 'preview')
inputs:
command: push
packagesToPush: '$(Build.Repository.LocalPath)\artifacts\*.nupkg'
publishVstsFeed: '46419298-b96c-437f-bd4c-12c8df7f868d'
allowPackageConflicts: true

- task: PublishBuildArtifacts@1
displayName: 'Publish NuGet Package Artifact'
inputs:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ public partial class JsonWebToken
{
internal JsonClaimSet CreateHeaderClaimSet(byte[] bytes)
{
return CreateHeaderClaimSet(bytes, bytes.Length);
return CreateHeaderClaimSet(bytes.AsSpan());
}

internal JsonClaimSet CreateHeaderClaimSet(byte[] bytes, int length)
{
Utf8JsonReader reader = new(bytes.AsSpan().Slice(0, length));
return CreateHeaderClaimSet(bytes.AsSpan(0, length));
}

internal JsonClaimSet CreateHeaderClaimSet(ReadOnlySpan<byte> byteSpan)
{
Utf8JsonReader reader = new(byteSpan);
if (!JsonSerializerPrimitives.IsReaderAtTokenType(ref reader, JsonTokenType.StartObject, true))
throw LogHelper.LogExceptionMessage(
new JsonException(
Expand Down Expand Up @@ -73,7 +78,7 @@ internal JsonClaimSet CreateHeaderClaimSet(byte[] bytes, int length)
}
}
// We read a JsonTokenType.StartObject above, exiting and positioning reader at next token.
else if (JsonSerializerPrimitives.IsReaderAtTokenType(ref reader, JsonTokenType.EndObject, true))
else if (JsonSerializerPrimitives.IsReaderAtTokenType(ref reader, JsonTokenType.EndObject, false))
break;
else if (!reader.Read())
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ public partial class JsonWebToken
{
internal JsonClaimSet CreatePayloadClaimSet(byte[] bytes, int length)
{
Utf8JsonReader reader = new(bytes.AsSpan().Slice(0, length));
return CreatePayloadClaimSet(bytes.AsSpan(0, length));
}

internal JsonClaimSet CreatePayloadClaimSet(ReadOnlySpan<byte> byteSpan)
{
Utf8JsonReader reader = new(byteSpan);
if (!JsonSerializerPrimitives.IsReaderAtTokenType(ref reader, JsonTokenType.StartObject, true))
throw LogHelper.LogExceptionMessage(
new JsonException(
Expand All @@ -27,14 +32,14 @@ internal JsonClaimSet CreatePayloadClaimSet(byte[] bytes, int length)
LogHelper.MarkAsNonPII(reader.CurrentDepth),
LogHelper.MarkAsNonPII(reader.BytesConsumed))));

Dictionary<string, object> claims = new();
Dictionary<string, object> claims = [];
while (true)
{
if (reader.TokenType == JsonTokenType.PropertyName)
{
if (reader.ValueTextEquals(JwtPayloadUtf8Bytes.Aud))
{
_audiences = new List<string>();
_audiences = [];
reader.Read();
if (reader.TokenType == JsonTokenType.StartArray)
{
Expand Down Expand Up @@ -99,7 +104,7 @@ internal JsonClaimSet CreatePayloadClaimSet(byte[] bytes, int length)
}
}
// We read a JsonTokenType.StartObject above, exiting and positioning reader at next token.
else if (JsonSerializerPrimitives.IsReaderAtTokenType(ref reader, JsonTokenType.EndObject, true))
else if (JsonSerializerPrimitives.IsReaderAtTokenType(ref reader, JsonTokenType.EndObject, false))
break;
else if (!reader.Read())
break;
Expand Down
Loading

0 comments on commit d5dc77e

Please sign in to comment.