Skip to content

Commit fee9715

Browse files
authored
Migrate from Newtonsoft to System.Text.Json (#249)
* Migrate from Newtonsoft to System.Text.Json * Add fast path for decoding UTF8-encoded Base64Url data * Ensure x5c is an Array * Add Async suffix to GetMetadataStatement * Remove trailing spaces * Add FidoEnumConverter test coverage * Extend FidoEnumConverter test coverage * [Demo] Use built-in System.Text.Json serializer
1 parent 3560dff commit fee9715

File tree

67 files changed

+817
-549
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+817
-549
lines changed

Demo/ConformanceTesting.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public static IMetadataService MetadataServiceInstance(string cacheDir, string o
2323
new FileSystemMetadataRepository(cacheDir)
2424
};
2525
_instance = new SimpleMetadataService(repos);
26-
_instance.Initialize().Wait();
26+
_instance.InitializeAsync().Wait();
2727
}
2828
}
2929
}

Demo/Demo.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
<ProjectReference Include="..\Src\Fido2.AspNet\Fido2.AspNet.csproj" />
88
<ProjectReference Include="..\Src\Fido2.Models\Fido2.Models.csproj" />
99
<ProjectReference Include="..\Src\Fido2\Fido2.csproj" />
10-
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.10" />
11-
1210
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
1311
</ItemGroup>
1412
<ItemGroup>

Demo/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void ConfigureServices(IServiceCollection services)
2626
{
2727
// we don't care about antiforgery in the demo
2828
opts.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
29-
}).AddNewtonsoftJson(); // the FIDO2 library requires Json.NET
29+
});
3030

3131
// Use the in-memory implementation of IDistributedCache.
3232
services.AddDistributedMemoryCache();

Src/Fido2.AspNet/DistributedCacheMetadataService.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.Linq;
5+
using System.Text.Json;
56
using System.Threading.Tasks;
67
using Microsoft.Extensions.Caching.Distributed;
78
using Microsoft.Extensions.Logging;
8-
using Newtonsoft.Json;
99

1010
namespace Fido2NetLib
1111
{
@@ -86,7 +86,7 @@ protected virtual async Task LoadTocEntryStatement(
8686
var cachedEntry = await _cache.GetStringAsync(cacheKey);
8787
if (cachedEntry != null)
8888
{
89-
var statement = JsonConvert.DeserializeObject<MetadataStatement>(cachedEntry);
89+
var statement = JsonSerializer.Deserialize<MetadataStatement>(cachedEntry);
9090
if (!string.IsNullOrWhiteSpace(statement.AaGuid))
9191
{
9292
var aaGuid = Guid.Parse(statement.AaGuid);
@@ -102,7 +102,7 @@ protected virtual async Task LoadTocEntryStatement(
102102
{
103103
if (!string.IsNullOrWhiteSpace(entry.AaGuid))
104104
{
105-
var statementJson = JsonConvert.SerializeObject(entry.MetadataStatement, Formatting.Indented);
105+
var statementJson = JsonSerializer.Serialize(entry.MetadataStatement, new JsonSerializerOptions { WriteIndented = true });
106106

107107
_log?.LogDebug("{0}:{1}\n{2}", entry.AaGuid, entry.MetadataStatement.Description, statementJson);
108108

@@ -149,7 +149,7 @@ protected virtual async Task LoadTocEntryStatement(
149149
return null;
150150
}
151151

152-
protected virtual async Task InitializeRepository(IMetadataRepository repository)
152+
protected virtual async Task InitializeRepositoryAsync(IMetadataRepository repository)
153153
{
154154
var blobCacheKey = GetTocCacheKey(repository);
155155

@@ -161,7 +161,7 @@ protected virtual async Task InitializeRepository(IMetadataRepository repository
161161

162162
if (cachedToc != null)
163163
{
164-
blob = JsonConvert.DeserializeObject<MetadataBLOBPayload>(cachedToc);
164+
blob = JsonSerializer.Deserialize<MetadataBLOBPayload>(cachedToc);
165165
cacheUntil = GetCacheUntilTime(blob);
166166
}
167167
else
@@ -186,7 +186,7 @@ protected virtual async Task InitializeRepository(IMetadataRepository repository
186186
{
187187
await _cache.SetStringAsync(
188188
blobCacheKey,
189-
JsonConvert.SerializeObject(blob),
189+
JsonSerializer.Serialize(blob),
190190
new DistributedCacheEntryOptions()
191191
{
192192
AbsoluteExpiration = cacheUntil
@@ -204,19 +204,19 @@ await _cache.SetStringAsync(
204204
}
205205
catch (Exception ex)
206206
{
207-
_log?.LogError(ex, "Error getting statement from {0} for AAGUID '{1}'.\nTOC entry:\n{2} ", repository.GetType().Name, entry.AaGuid, JsonConvert.SerializeObject(entry, Formatting.Indented));
207+
_log?.LogError(ex, "Error getting statement from {0} for AAGUID '{1}'.\nTOC entry:\n{2} ", repository.GetType().Name, entry.AaGuid, JsonSerializer.Serialize(entry, new JsonSerializerOptions { WriteIndented = true }));
208208
}
209209
}
210210
}
211211
}
212212

213-
public virtual async Task Initialize()
213+
public virtual async Task InitializeAsync()
214214
{
215215
foreach (var repository in _repositories)
216216
{
217217
try
218218
{
219-
await InitializeRepository(repository);
219+
await InitializeRepositoryAsync(repository);
220220
}
221221
catch (Exception ex)
222222
{

Src/Fido2.AspNet/Fido2NetLibBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ private static void AddMetadataService<TService>(this IFido2NetLibBuilder builde
8787
builder.Services.AddSingleton<IMetadataService>(r =>
8888
{
8989
var service = r.GetService<TService>();
90-
service.Initialize().Wait();
90+
service.InitializeAsync().Wait();
9191
return service;
9292
});
9393
}

Src/Fido2.AspNet/NullMetadataService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ MetadataBLOBPayloadEntry IMetadataService.GetEntry(Guid aaguid)
1515
return null;
1616
}
1717

18-
Task IMetadataService.Initialize()
18+
Task IMetadataService.InitializeAsync()
1919
{
2020
return Task.CompletedTask;
2121
}

Src/Fido2.Models/AssertionOptions.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Collections.Generic;
2+
using System.Text.Json;
3+
using System.Text.Json.Serialization;
4+
25
using Fido2NetLib.Objects;
3-
using Newtonsoft.Json;
46

57
namespace Fido2NetLib
68
{
@@ -12,38 +14,39 @@ public class AssertionOptions : Fido2ResponseBase
1214
/// <summary>
1315
/// This member represents a challenge that the selected authenticator signs, along with other data, when producing an authentication assertion.See the §13.1 Cryptographic Challenges security consideration.
1416
/// </summary>
15-
[JsonProperty("challenge")]
17+
[JsonPropertyName("challenge")]
1618
[JsonConverter(typeof(Base64UrlConverter))]
1719
public byte[] Challenge { get; set; }
1820

1921
/// <summary>
2022
/// This member specifies a time, in milliseconds, that the caller is willing to wait for the call to complete. This is treated as a hint, and MAY be overridden by the client.
2123
/// </summary>
22-
[JsonProperty("timeout")]
24+
[JsonPropertyName("timeout")]
2325
public uint Timeout { get; set; }
2426

2527
/// <summary>
2628
/// This OPTIONAL member specifies the relying party identifier claimed by the caller.If omitted, its value will be the CredentialsContainer object’s relevant settings object's origin's effective domain
2729
/// </summary>
28-
[JsonProperty("rpId")]
30+
[JsonPropertyName("rpId")]
2931
public string RpId { get; set; }
3032

3133
/// <summary>
3234
/// This OPTIONAL member contains a list of PublicKeyCredentialDescriptor objects representing public key credentials acceptable to the caller, in descending order of the caller’s preference(the first item in the list is the most preferred credential, and so on down the list)
3335
/// </summary>
34-
[JsonProperty("allowCredentials")]
36+
[JsonPropertyName("allowCredentials")]
3537
public IEnumerable<PublicKeyCredentialDescriptor> AllowCredentials { get; set; }
3638

3739
/// <summary>
3840
/// This member describes the Relying Party's requirements regarding user verification for the get() operation. Eligible authenticators are filtered to only those capable of satisfying this requirement
3941
/// </summary>
40-
[JsonProperty("userVerification")]
42+
[JsonPropertyName("userVerification")]
4143
public UserVerificationRequirement? UserVerification { get; set; }
4244

4345
/// <summary>
4446
/// This OPTIONAL member contains additional parameters requesting additional processing by the client and authenticator. For example, if transaction confirmation is sought from the user, then the prompt string might be included as an extension.
4547
/// </summary>
46-
[JsonProperty("extensions", NullValueHandling = NullValueHandling.Ignore)]
48+
[JsonPropertyName("extensions")]
49+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
4750
public AuthenticationExtensionsClientInputs Extensions { get; set; }
4851

4952
public static AssertionOptions Create(Fido2Configuration config, byte[] challenge, IEnumerable<PublicKeyCredentialDescriptor> allowedCredentials, UserVerificationRequirement? userVerification, AuthenticationExtensionsClientInputs extensions)
@@ -63,12 +66,12 @@ public static AssertionOptions Create(Fido2Configuration config, byte[] challeng
6366

6467
public string ToJson()
6568
{
66-
return JsonConvert.SerializeObject(this);
69+
return JsonSerializer.Serialize(this);
6770
}
6871

6972
public static AssertionOptions FromJson(string json)
7073
{
71-
return JsonConvert.DeserializeObject<AssertionOptions>(json);
74+
return JsonSerializer.Deserialize<AssertionOptions>(json);
7275
}
7376
}
7477
}

Src/Fido2.Models/AuthenticatorAssertionRawResponse.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#nullable disable
22

3-
using Newtonsoft.Json;
3+
using System.Text.Json.Serialization;
4+
45
using Fido2NetLib.Objects;
56

67
namespace Fido2NetLib
@@ -11,32 +12,39 @@ namespace Fido2NetLib
1112
public class AuthenticatorAssertionRawResponse
1213
{
1314
[JsonConverter(typeof(Base64UrlConverter))]
15+
[JsonPropertyName("id")]
1416
public byte[] Id { get; set; }
1517

1618
// might be wrong to base64url encode this...
1719
[JsonConverter(typeof(Base64UrlConverter))]
20+
[JsonPropertyName("rawId")]
1821
public byte[] RawId { get; set; }
1922

23+
[JsonPropertyName("response")]
2024
public AssertionResponse Response { get; set; }
2125

26+
[JsonPropertyName("type")]
2227
public PublicKeyCredentialType? Type { get; set; }
2328

29+
[JsonPropertyName("extensions")]
2430
public AuthenticationExtensionsClientOutputs Extensions { get; set; }
2531

2632
public class AssertionResponse
2733
{
2834
[JsonConverter(typeof(Base64UrlConverter))]
35+
[JsonPropertyName("authenticatorData")]
2936
public byte[] AuthenticatorData { get; set; }
3037

3138
[JsonConverter(typeof(Base64UrlConverter))]
39+
[JsonPropertyName("signature")]
3240
public byte[] Signature { get; set; }
3341

34-
[JsonProperty("clientDataJson")]
3542
[JsonConverter(typeof(Base64UrlConverter))]
43+
[JsonPropertyName("clientDataJSON")]
3644
public byte[] ClientDataJson { get; set; }
3745

38-
[JsonProperty("userHandle")]
39-
[JsonConverter(typeof(Base64UrlConverter), Required.AllowNull)]
46+
[JsonPropertyName("userHandle")]
47+
[JsonConverter(typeof(Base64UrlConverter))]
4048
public byte[] UserHandle { get; set; }
4149
}
4250
}

Src/Fido2.Models/AuthenticatorAttestationRawResponse.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,36 @@
1-
using Newtonsoft.Json;
1+
using System.Text.Json.Serialization;
2+
23
using Fido2NetLib.Objects;
34

45
namespace Fido2NetLib
56
{
6-
public class AuthenticatorAttestationRawResponse
7+
public sealed class AuthenticatorAttestationRawResponse
78
{
89
[JsonConverter(typeof(Base64UrlConverter))]
10+
[JsonPropertyName("id")]
911
public byte[] Id { get; set; }
1012

1113
[JsonConverter(typeof(Base64UrlConverter))]
14+
[JsonPropertyName("rawId")]
1215
public byte[] RawId { get; set; }
1316

17+
[JsonPropertyName("type")]
1418
public PublicKeyCredentialType? Type { get; set; }
1519

20+
[JsonPropertyName("response")]
1621
public ResponseData Response { get; set; }
1722

23+
[JsonPropertyName("extensions")]
1824
public AuthenticationExtensionsClientOutputs Extensions { get; set; }
1925

20-
public class ResponseData
26+
public sealed class ResponseData
2127
{
2228
[JsonConverter(typeof(Base64UrlConverter))]
29+
[JsonPropertyName("attestationObject")]
2330
public byte[] AttestationObject { get; set; }
31+
2432
[JsonConverter(typeof(Base64UrlConverter))]
33+
[JsonPropertyName("clientDataJSON")]
2534
public byte[] ClientDataJson { get; set; }
2635
}
2736
}

Src/Fido2.Models/Base64Converter.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)