Skip to content

Commit db931bd

Browse files
authored
Add CancellationToken to Task methods (#278)
* Add CancellationToken to Task methods * Drop (some) trailing spaces * Add =default to all cancellationToken in public methods * Re-add requestTokenBindingId = null
1 parent 54761b0 commit db931bd

23 files changed

+350
-301
lines changed

.editorconfig

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ dotnet_style_explicit_tuple_names = true:suggestion
6060
[*.cs]
6161
# Prefer "var" when the type is apparent on the right side of the assignment; otherwise, avoid it.
6262
csharp_style_var_when_type_is_apparent = true:suggestion
63-
csharp_style_var_elsewhere = false:suggestion
63+
csharp_style_var_elsewhere = true:suggestion
6464

6565
# Prefer method-like constructs to have a block body
6666
csharp_style_expression_bodied_methods = false:none
@@ -162,4 +162,9 @@ dotnet_naming_style.begins_with_underscore.capitalization = camel_case
162162
dotnet_naming_style.ends_with_async.required_prefix =
163163
dotnet_naming_style.ends_with_async.required_suffix = Async
164164
dotnet_naming_style.ends_with_async.word_separator =
165-
dotnet_naming_style.ends_with_async.capitalization = pascal_case
165+
dotnet_naming_style.ends_with_async.capitalization = pascal_case
166+
167+
# Code analysis
168+
169+
dotnet_diagnostic.CA2016.severity = error
170+
dotnet_diagnostic.CS1591.severity = silent

Demo/Controller.cs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Text;
5-
using System.Threading.Tasks;
5+
using System.Threading;
6+
using System.Threading.Tasks;
67
using Fido2NetLib;
78
using Fido2NetLib.Development;
8-
using Fido2NetLib.Objects;
9+
using Fido2NetLib.Objects;
910
using Microsoft.AspNetCore.Http;
1011
using Microsoft.AspNetCore.Mvc;
11-
12+
1213
using static Fido2NetLib.Fido2;
13-
14+
1415
namespace Fido2Demo
1516
{
1617
[Route("api/[controller]")]
@@ -22,7 +23,7 @@ public class MyController : Controller
2223

2324
public MyController(IFido2 fido2)
2425
{
25-
_fido2 = fido2;
26+
_fido2 = fido2;
2627
}
2728

2829
private string FormatException(Exception e)
@@ -32,11 +33,11 @@ private string FormatException(Exception e)
3233

3334
[HttpPost]
3435
[Route("/makeCredentialOptions")]
35-
public JsonResult MakeCredentialOptions([FromForm] string username,
36-
[FromForm] string displayName,
37-
[FromForm] string attType,
38-
[FromForm] string authType,
39-
[FromForm] bool requireResidentKey,
36+
public JsonResult MakeCredentialOptions([FromForm] string username,
37+
[FromForm] string displayName,
38+
[FromForm] string attType,
39+
[FromForm] string authType,
40+
[FromForm] bool requireResidentKey,
4041
[FromForm] string userVerification)
4142
{
4243
try
@@ -90,7 +91,7 @@ public JsonResult MakeCredentialOptions([FromForm] string username,
9091

9192
[HttpPost]
9293
[Route("/makeCredential")]
93-
public async Task<JsonResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse attestationResponse)
94+
public async Task<JsonResult> MakeCredential([FromBody] AuthenticatorAttestationRawResponse attestationResponse, CancellationToken cancellationToken)
9495
{
9596
try
9697
{
@@ -99,17 +100,17 @@ public async Task<JsonResult> MakeCredential([FromBody] AuthenticatorAttestation
99100
var options = CredentialCreateOptions.FromJson(jsonOptions);
100101

101102
// 2. Create callback so that lib can verify credential id is unique to this user
102-
IsCredentialIdUniqueToUserAsyncDelegate callback = async (IsCredentialIdUniqueToUserParams args) =>
103+
IsCredentialIdUniqueToUserAsyncDelegate callback = static async (args, cancellationToken) =>
103104
{
104-
var users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId);
105+
var users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId, cancellationToken);
105106
if (users.Count > 0)
106107
return false;
107108

108109
return true;
109110
};
110111

111112
// 2. Verify and make the credentials
112-
var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback);
113+
var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken);
113114

114115
// 3. Store the credentials in db
115116
DemoStorage.AddCredentialToUser(options.User, new StoredCredential
@@ -177,7 +178,7 @@ public ActionResult AssertionOptionsPost([FromForm] string username, [FromForm]
177178

178179
[HttpPost]
179180
[Route("/makeAssertion")]
180-
public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRawResponse clientResponse)
181+
public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRawResponse clientResponse, CancellationToken cancellationToken)
181182
{
182183
try
183184
{
@@ -192,14 +193,14 @@ public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRaw
192193
var storedCounter = creds.SignatureCounter;
193194

194195
// 4. Create callback to check if userhandle owns the credentialId
195-
IsUserHandleOwnerOfCredentialIdAsync callback = async (args) =>
196+
IsUserHandleOwnerOfCredentialIdAsync callback = static async (args, cancellationToken) =>
196197
{
197-
var storedCreds = await DemoStorage.GetCredentialsByUserHandleAsync(args.UserHandle);
198+
var storedCreds = await DemoStorage.GetCredentialsByUserHandleAsync(args.UserHandle, cancellationToken);
198199
return storedCreds.Exists(c => c.Descriptor.Id.SequenceEqual(args.CredentialId));
199200
};
200201

201202
// 5. Make the assertion
202-
var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, storedCounter, callback);
203+
var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, storedCounter, callback, cancellationToken: cancellationToken);
203204

204205
// 6. Store the updated counter
205206
DemoStorage.UpdateCounter(res.CredentialId, res.Counter);

Demo/TestController.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Linq;
33
using System.Text;
4+
using System.Threading;
45
using System.Threading.Tasks;
56
using Fido2NetLib;
67
using Fido2NetLib.Development;
@@ -80,22 +81,22 @@ public JsonResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialParams
8081

8182
[HttpPost]
8283
[Route("/attestation/result")]
83-
public async Task<JsonResult> MakeCredentialResultTest([FromBody] AuthenticatorAttestationRawResponse attestationResponse)
84+
public async Task<JsonResult> MakeCredentialResultTest([FromBody] AuthenticatorAttestationRawResponse attestationResponse, CancellationToken cancellationToken)
8485
{
8586

8687
// 1. get the options we sent the client
8788
var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
8889
var options = CredentialCreateOptions.FromJson(jsonOptions);
8990

9091
// 2. Create callback so that lib can verify credential id is unique to this user
91-
IsCredentialIdUniqueToUserAsyncDelegate callback = async (IsCredentialIdUniqueToUserParams args) =>
92+
IsCredentialIdUniqueToUserAsyncDelegate callback = static async (args, cancellationToken) =>
9293
{
93-
var users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId);
94+
var users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId, cancellationToken);
9495
return users.Count <= 0;
9596
};
9697

9798
// 2. Verify and make the credentials
98-
var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback);
99+
var success = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken);
99100

100101
// 3. Store the credentials in db
101102
DemoStorage.AddCredentialToUser(options.User, new StoredCredential
@@ -151,7 +152,7 @@ public IActionResult AssertionOptionsTest([FromBody] TEST_AssertionClientParams
151152

152153
[HttpPost]
153154
[Route("/assertion/result")]
154-
public async Task<JsonResult> MakeAssertionTest([FromBody] AuthenticatorAssertionRawResponse clientResponse)
155+
public async Task<JsonResult> MakeAssertionTest([FromBody] AuthenticatorAssertionRawResponse clientResponse, CancellationToken cancellationToken)
155156
{
156157
// 1. Get the assertion options we sent the client
157158
var jsonOptions = HttpContext.Session.GetString("fido2.assertionOptions");
@@ -164,14 +165,14 @@ public async Task<JsonResult> MakeAssertionTest([FromBody] AuthenticatorAssertio
164165
var storedCounter = creds.SignatureCounter;
165166

166167
// 4. Create callback to check if userhandle owns the credentialId
167-
IsUserHandleOwnerOfCredentialIdAsync callback = async (args) =>
168+
IsUserHandleOwnerOfCredentialIdAsync callback = static async (args, cancellationToken) =>
168169
{
169-
var storedCreds = await DemoStorage.GetCredentialsByUserHandleAsync(args.UserHandle);
170+
var storedCreds = await DemoStorage.GetCredentialsByUserHandleAsync(args.UserHandle, cancellationToken);
170171
return storedCreds.Exists(c => c.Descriptor.Id.SequenceEqual(args.CredentialId));
171172
};
172173

173174
// 5. Make the assertion
174-
var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, storedCounter, callback);
175+
var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, storedCounter, callback, cancellationToken: cancellationToken);
175176

176177
// 6. Store the updated counter
177178
DemoStorage.UpdateCounter(res.CredentialId, res.Counter);

Src/Fido2.AspNet/DistributedCacheMetadataService.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Linq;
55
using System.Text.Json;
6+
using System.Threading;
67
using System.Threading.Tasks;
78
using Microsoft.Extensions.Caching.Distributed;
89
using Microsoft.Extensions.Logging;
@@ -36,7 +37,7 @@ public DistributedCacheMetadataService(
3637

3738
public virtual bool ConformanceTesting()
3839
{
39-
return _repositories.First().GetType() == typeof(ConformanceMetadataRepository);
40+
return _repositories.First() is ConformanceMetadataRepository;
4041
}
4142

4243
public virtual MetadataBLOBPayloadEntry GetEntry(Guid aaguid)
@@ -147,11 +148,11 @@ protected virtual async Task LoadTocEntryStatement(
147148
return null;
148149
}
149150

150-
protected virtual async Task InitializeRepositoryAsync(IMetadataRepository repository)
151+
protected virtual async Task InitializeRepositoryAsync(IMetadataRepository repository, CancellationToken cancellationToken)
151152
{
152153
var blobCacheKey = GetTocCacheKey(repository);
153154

154-
var cachedToc = await _cache.GetStringAsync(blobCacheKey);
155+
var cachedToc = await _cache.GetStringAsync(blobCacheKey, cancellationToken);
155156

156157
MetadataBLOBPayload blob;
157158

@@ -168,7 +169,7 @@ protected virtual async Task InitializeRepositoryAsync(IMetadataRepository repos
168169

169170
try
170171
{
171-
blob = await repository.GetBLOBAsync();
172+
blob = await repository.GetBLOBAsync(cancellationToken);
172173
}
173174
catch (Exception ex)
174175
{
@@ -188,7 +189,8 @@ await _cache.SetStringAsync(
188189
new DistributedCacheEntryOptions()
189190
{
190191
AbsoluteExpiration = cacheUntil
191-
});
192+
},
193+
cancellationToken);
192194
}
193195
}
194196

@@ -208,13 +210,13 @@ await _cache.SetStringAsync(
208210
}
209211
}
210212

211-
public virtual async Task InitializeAsync()
213+
public virtual async Task InitializeAsync(CancellationToken cancellationToken = default)
212214
{
213215
foreach (var repository in _repositories)
214216
{
215217
try
216218
{
217-
await InitializeRepositoryAsync(repository);
219+
await InitializeRepositoryAsync(repository, cancellationToken);
218220
}
219221
catch (Exception ex)
220222
{

Src/Fido2.AspNet/NullMetadataService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading;
23
using System.Threading.Tasks;
34

45
namespace Fido2NetLib
@@ -15,7 +16,7 @@ MetadataBLOBPayloadEntry IMetadataService.GetEntry(Guid aaguid)
1516
return null;
1617
}
1718

18-
Task IMetadataService.InitializeAsync()
19+
Task IMetadataService.InitializeAsync(CancellationToken cancellationToken)
1920
{
2021
return Task.CompletedTask;
2122
}

Src/Fido2/AttestationFormat/Tpm.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,15 @@ public override (AttestationType, X509Certificate2[]) Verify()
117117
var alg = (COSE.Algorithm)(int)Alg;
118118

119119
ReadOnlySpan<byte> dataHash = CryptoUtils.HashData(CryptoUtils.HashAlgFromCOSEAlg(alg), Data);
120-
120+
121121
if (!dataHash.SequenceEqual(certInfo.ExtraData))
122122
throw new Fido2VerificationException("Hash value mismatch extraData and attToBeSigned");
123-
123+
124124
// 4d. Verify that attested contains a TPMS_CERTIFY_INFO structure, whose name field contains a valid Name for pubArea, as computed using the algorithm in the nameAlg field of pubArea
125125
ReadOnlySpan<byte> pubAreaRawHash = CryptoUtils.HashData(CryptoUtils.HashAlgFromCOSEAlg((COSE.Algorithm)certInfo.Alg), pubArea.Raw);
126-
126+
127127
if (!pubAreaRawHash.SequenceEqual(certInfo.AttestedName))
128-
throw new Fido2VerificationException("Hash value mismatch attested and pubArea");
128+
throw new Fido2VerificationException("Hash value mismatch attested and pubArea");
129129

130130
// 4e. Note that the remaining fields in the "Standard Attestation Structure" [TPMv2-Part1] section 31.2, i.e., qualifiedSigner, clockInfo and firmwareVersion are ignored. These fields MAY be used as an input to risk engines.
131131

Src/Fido2/AuthenticatorAssertionResponse.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
using System;
22
using System.Collections.Generic;
3-
4-
#nullable disable
5-
63
using System.Linq;
74
using System.Security.Cryptography;
85
using System.Text;
6+
using System.Threading;
97
using System.Threading.Tasks;
108
using Fido2NetLib.Objects;
119

10+
#nullable disable
11+
1212
namespace Fido2NetLib
1313
{
1414
/// <summary>
@@ -53,13 +53,15 @@ public static AuthenticatorAssertionResponse Parse(AuthenticatorAssertionRawResp
5353
/// <param name="storedSignatureCounter">The stored counter value for this CredentialId</param>
5454
/// <param name="isUserHandleOwnerOfCredId">A function that returns <see langword="true"/> if user handle is owned by the credential ID</param>
5555
/// <param name="requestTokenBindingId"></param>
56+
/// <param name="cancellationToken"></param>
5657
public async Task<AssertionVerificationResult> VerifyAsync(
5758
AssertionOptions options,
5859
HashSet<string> fullyQualifiedExpectedOrigins,
5960
byte[] storedPublicKey,
6061
uint storedSignatureCounter,
6162
IsUserHandleOwnerOfCredentialIdAsync isUserHandleOwnerOfCredId,
62-
byte[] requestTokenBindingId)
63+
byte[] requestTokenBindingId,
64+
CancellationToken cancellationToken = default)
6365
{
6466
BaseVerify(fullyQualifiedExpectedOrigins, options.Challenge, requestTokenBindingId);
6567

@@ -86,7 +88,7 @@ public async Task<AssertionVerificationResult> VerifyAsync(
8688
if (UserHandle.Length is 0)
8789
throw new Fido2VerificationException("Userhandle was empty DOMString. It should either be null or have a value.");
8890

89-
if (false == await isUserHandleOwnerOfCredId(new IsUserHandleOwnerOfCredentialIdParams(Raw.Id, UserHandle)))
91+
if (false == await isUserHandleOwnerOfCredId(new IsUserHandleOwnerOfCredentialIdParams(Raw.Id, UserHandle), cancellationToken))
9092
{
9193
throw new Fido2VerificationException("User is not owner of the public key identitief by the credential id");
9294
}

Src/Fido2/AuthenticatorAttestationResponse.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Security.Cryptography;
66
using System.Security.Cryptography.X509Certificates;
77
using System.Text;
8+
using System.Threading;
89
using System.Threading.Tasks;
910

1011
using Fido2NetLib.Cbor;
@@ -70,7 +71,13 @@ public static AuthenticatorAttestationResponse Parse(AuthenticatorAttestationRaw
7071
return response;
7172
}
7273

73-
public async Task<AttestationVerificationSuccess> VerifyAsync(CredentialCreateOptions originalOptions, Fido2Configuration config, IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser, IMetadataService metadataService, byte[] requestTokenBindingId)
74+
public async Task<AttestationVerificationSuccess> VerifyAsync(
75+
CredentialCreateOptions originalOptions,
76+
Fido2Configuration config,
77+
IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser,
78+
IMetadataService metadataService,
79+
byte[] requestTokenBindingId,
80+
CancellationToken cancellationToken = default)
7481
{
7582
// https://www.w3.org/TR/webauthn/#registering-a-new-credential
7683
// 1. Let JSONtext be the result of running UTF-8 decode on the value of response.clientDataJSON.
@@ -216,7 +223,7 @@ static bool ContainsAttestationType(MetadataBLOBPayloadEntry entry, MetadataAtte
216223

217224
// 17. Check that the credentialId is not yet registered to any other user.
218225
// If registration is requested for a credential that is already registered to a different user, the Relying Party SHOULD fail this registration ceremony, or it MAY decide to accept the registration, e.g. while deleting the older registration
219-
if (false == await isCredentialIdUniqueToUser(new IsCredentialIdUniqueToUserParams(authData.AttestedCredentialData.CredentialID, originalOptions.User)))
226+
if (false == await isCredentialIdUniqueToUser(new IsCredentialIdUniqueToUserParams(authData.AttestedCredentialData.CredentialID, originalOptions.User), cancellationToken))
220227
{
221228
throw new Fido2VerificationException("CredentialId is not unique to this user");
222229
}

Src/Fido2/DevelopmentInMemoryStore.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.Linq;
5+
using System.Threading;
56
using System.Threading.Tasks;
67
using Fido2NetLib.Objects;
78

@@ -33,7 +34,7 @@ public List<StoredCredential> GetCredentialsByUser(Fido2User user)
3334
return _storedCredentials.FirstOrDefault(c => c.Descriptor.Id.AsSpan().SequenceEqual(id));
3435
}
3536

36-
public Task<List<StoredCredential>> GetCredentialsByUserHandleAsync(byte[] userHandle)
37+
public Task<List<StoredCredential>> GetCredentialsByUserHandleAsync(byte[] userHandle, CancellationToken cancellationToken = default)
3738
{
3839
return Task.FromResult(_storedCredentials.Where(c => c.UserHandle.AsSpan().SequenceEqual(userHandle)).ToList());
3940
}
@@ -50,7 +51,7 @@ public void AddCredentialToUser(Fido2User user, StoredCredential credential)
5051
_storedCredentials.Add(credential);
5152
}
5253

53-
public Task<List<Fido2User>> GetUsersByCredentialIdAsync(byte[] credentialId)
54+
public Task<List<Fido2User>> GetUsersByCredentialIdAsync(byte[] credentialId, CancellationToken cancellationToken = default)
5455
{
5556
// our in-mem storage does not allow storing multiple users for a given credentialId. Yours shouldn't either.
5657
var cred = _storedCredentials.FirstOrDefault(c => c.Descriptor.Id.AsSpan().SequenceEqual(credentialId));

0 commit comments

Comments
 (0)