Skip to content

Commit b2e7c15

Browse files
authored
Wrap arguments into classes (#556)
* Wrap method arguments into classes * format * format * Seal the classes * Adress feedback
1 parent 72f5a36 commit b2e7c15

11 files changed

+1522
-1217
lines changed

BlazorWasmDemo/Server/Controllers/UserController.cs

+15-9
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,12 @@ public async Task<string> CreateCredentialAsync([FromRoute] string username, [Fr
150150
// 2. Create callback so that lib can verify credential id is unique to this user
151151

152152
// 3. Verify and make the credentials
153-
var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, CredentialIdUniqueToUserAsync, cancellationToken: cancellationToken);
153+
var credential = await _fido2.MakeNewCredentialAsync(new MakeNewCredentialParams
154+
{
155+
AttestationResponse = attestationResponse,
156+
OriginalOptions = options,
157+
IsCredentialIdUniqueToUserCallback = CredentialIdUniqueToUserAsync
158+
}, cancellationToken: cancellationToken);
154159

155160
// 4. Store the credentials in db
156161
_demoStorage.AddCredentialToUser(options.User, new StoredCredential
@@ -266,14 +271,15 @@ public async Task<string> MakeAssertionAsync([FromBody] AuthenticatorAssertionRa
266271
var creds = _demoStorage.GetCredentialById(clientResponse.Id) ?? throw new Exception("Unknown credentials");
267272

268273
// 3. Make the assertion
269-
var res = await _fido2.MakeAssertionAsync(
270-
clientResponse,
271-
options,
272-
creds.PublicKey,
273-
creds.DevicePublicKeys,
274-
creds.SignCount,
275-
UserHandleOwnerOfCredentialIdAsync,
276-
cancellationToken: cancellationToken);
274+
var res = await _fido2.MakeAssertionAsync(new MakeAssertionParams
275+
{
276+
AssertionResponse = clientResponse,
277+
OriginalOptions = options,
278+
StoredPublicKey = creds.PublicKey,
279+
StoredSignatureCounter = creds.SignCount,
280+
IsUserHandleOwnerOfCredentialIdCallback = UserHandleOwnerOfCredentialIdAsync,
281+
StoredDevicePublicKeys = creds.DevicePublicKeys
282+
}, cancellationToken: cancellationToken);
277283

278284
// 4. Store the updated counter
279285
_demoStorage.UpdateCounter(res.CredentialId, res.SignCount);

Demo/Controller.cs

+15-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,12 @@ public async Task<JsonResult> MakeCredential([FromBody] AuthenticatorAttestation
106106
};
107107

108108
// 2. Verify and make the credentials
109-
var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken);
109+
var credential = await _fido2.MakeNewCredentialAsync(new MakeNewCredentialParams
110+
{
111+
AttestationResponse = attestationResponse,
112+
OriginalOptions = options,
113+
IsCredentialIdUniqueToUserCallback = callback
114+
}, cancellationToken: cancellationToken);
110115

111116
// 3. Store the credentials in db
112117
DemoStorage.AddCredentialToUser(options.User, new StoredCredential
@@ -204,7 +209,15 @@ public async Task<JsonResult> MakeAssertion([FromBody] AuthenticatorAssertionRaw
204209
};
205210

206211
// 5. Make the assertion
207-
var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, creds.DevicePublicKeys, storedCounter, callback, cancellationToken: cancellationToken);
212+
var res = await _fido2.MakeAssertionAsync(new MakeAssertionParams
213+
{
214+
AssertionResponse = clientResponse,
215+
OriginalOptions = options,
216+
StoredPublicKey = creds.PublicKey,
217+
StoredSignatureCounter = storedCounter,
218+
IsUserHandleOwnerOfCredentialIdCallback = callback,
219+
StoredDevicePublicKeys = creds.DevicePublicKeys
220+
}, cancellationToken: cancellationToken);
208221

209222
// 6. Store the updated counter
210223
DemoStorage.UpdateCounter(res.CredentialId, res.SignCount);

Demo/TestController.cs

+15-2
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,12 @@ public async Task<OkObjectResult> MakeCredentialResultTestAsync([FromBody] Authe
9595
};
9696

9797
// 2. Verify and make the credentials
98-
var credential = await _fido2.MakeNewCredentialAsync(attestationResponse, options, callback, cancellationToken: cancellationToken);
98+
var credential = await _fido2.MakeNewCredentialAsync(new MakeNewCredentialParams
99+
{
100+
AttestationResponse = attestationResponse,
101+
OriginalOptions = options,
102+
IsCredentialIdUniqueToUserCallback = callback
103+
}, cancellationToken: cancellationToken);
99104

100105
// 3. Store the credentials in db
101106
_demoStorage.AddCredentialToUser(options.User, new StoredCredential
@@ -177,7 +182,15 @@ public async Task<JsonResult> MakeAssertionTestAsync([FromBody] AuthenticatorAss
177182
};
178183

179184
// 5. Make the assertion
180-
var res = await _fido2.MakeAssertionAsync(clientResponse, options, creds.PublicKey, creds.DevicePublicKeys, storedCounter, callback, cancellationToken: cancellationToken);
185+
var res = await _fido2.MakeAssertionAsync(new MakeAssertionParams
186+
{
187+
AssertionResponse = clientResponse,
188+
OriginalOptions = options,
189+
StoredPublicKey = creds.PublicKey,
190+
StoredSignatureCounter = storedCounter,
191+
IsUserHandleOwnerOfCredentialIdCallback = callback,
192+
StoredDevicePublicKeys = creds.DevicePublicKeys
193+
}, cancellationToken: cancellationToken);
181194

182195
// 6. Store the updated counter
183196
_demoStorage.UpdateCounter(res.CredentialId, res.SignCount);

Src/Fido2/Fido2.cs

+13-33
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,14 @@ public CredentialCreateOptions RequestNewCredential(
6262
/// <summary>
6363
/// Verifies the response from the browser/authenticator after creating new credentials.
6464
/// </summary>
65-
/// <param name="attestationResponse">The attestation response from the authenticator.</param>
66-
/// <param name="originalOptions">The original options that was sent to the client.</param>
67-
/// <param name="isCredentialIdUniqueToUser">The delegate used to validate that the CredentialID is unique to this user.</param>
68-
/// <param name="requestTokenBindingId">DO NOT USE - Deprecated, but kept in code due to conformance testing tool</param>
65+
/// <param name="makeNewCredentialParams">The input arguments for creating a passkey</param>
6966
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
7067
/// <returns></returns>
71-
public async Task<RegisteredPublicKeyCredential> MakeNewCredentialAsync(
72-
AuthenticatorAttestationRawResponse attestationResponse,
73-
CredentialCreateOptions originalOptions,
74-
IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser,
75-
byte[]? requestTokenBindingId = null,
68+
public async Task<RegisteredPublicKeyCredential> MakeNewCredentialAsync(MakeNewCredentialParams makeNewCredentialParams,
7669
CancellationToken cancellationToken = default)
7770
{
78-
var parsedResponse = AuthenticatorAttestationResponse.Parse(attestationResponse);
79-
var credential = await parsedResponse.VerifyAsync(originalOptions, _config, isCredentialIdUniqueToUser, _metadataService, requestTokenBindingId, cancellationToken);
71+
var parsedResponse = AuthenticatorAttestationResponse.Parse(makeNewCredentialParams.AttestationResponse);
72+
var credential = await parsedResponse.VerifyAsync(makeNewCredentialParams.OriginalOptions, _config, makeNewCredentialParams.IsCredentialIdUniqueToUserCallback, _metadataService, makeNewCredentialParams.RequestTokenBindingId, cancellationToken);
8073

8174
return credential;
8275
}
@@ -101,35 +94,22 @@ public AssertionOptions GetAssertionOptions(
10194
/// <summary>
10295
/// Verifies the assertion response from the browser/authenticator to assert existing credentials and authenticate a user.
10396
/// </summary>
104-
/// <param name="assertionResponse">The assertion response from the authenticator.</param>
105-
/// <param name="originalOptions">The original options that was sent to the client.</param>
106-
/// <param name="storedPublicKey">The stored credential public key.</param>
107-
/// <param name="storedDevicePublicKeys">The stored device public keys.</param>
108-
/// <param name="storedSignatureCounter">The stored value of the signature counter.</param>
109-
/// <param name="isUserHandleOwnerOfCredentialIdCallback">The delegate used to validate that the user handle is indeed owned of the CredentialId.</param>
110-
/// <param name="requestTokenBindingId">DO NOT USE - Deprecated, but kept in code due to conformance testing tool</param>
97+
/// <param name="makeAssertionParams">The input arguments for asserting a passkey</param>
11198
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
11299
/// <returns></returns>
113-
public async Task<VerifyAssertionResult> MakeAssertionAsync(
114-
AuthenticatorAssertionRawResponse assertionResponse,
115-
AssertionOptions originalOptions,
116-
byte[] storedPublicKey,
117-
IReadOnlyList<byte[]> storedDevicePublicKeys,
118-
uint storedSignatureCounter,
119-
IsUserHandleOwnerOfCredentialIdAsync isUserHandleOwnerOfCredentialIdCallback,
120-
byte[]? requestTokenBindingId = null,
100+
public async Task<VerifyAssertionResult> MakeAssertionAsync(MakeAssertionParams makeAssertionParams,
121101
CancellationToken cancellationToken = default)
122102
{
123-
var parsedResponse = AuthenticatorAssertionResponse.Parse(assertionResponse);
103+
var parsedResponse = AuthenticatorAssertionResponse.Parse(makeAssertionParams.AssertionResponse);
124104

125-
var result = await parsedResponse.VerifyAsync(originalOptions,
105+
var result = await parsedResponse.VerifyAsync(makeAssertionParams.OriginalOptions,
126106
_config,
127-
storedPublicKey,
128-
storedDevicePublicKeys,
129-
storedSignatureCounter,
130-
isUserHandleOwnerOfCredentialIdCallback,
107+
makeAssertionParams.StoredPublicKey,
108+
makeAssertionParams.StoredDevicePublicKeys,
109+
makeAssertionParams.StoredSignatureCounter,
110+
makeAssertionParams.IsUserHandleOwnerOfCredentialIdCallback,
131111
_metadataService,
132-
requestTokenBindingId,
112+
makeAssertionParams.RequestTokenBindingId,
133113
cancellationToken);
134114

135115
return result;

Src/Fido2/IFido2.cs

+2-13
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,10 @@ AssertionOptions GetAssertionOptions(
1313
UserVerificationRequirement? userVerification,
1414
AuthenticationExtensionsClientInputs? extensions = null);
1515

16-
Task<VerifyAssertionResult> MakeAssertionAsync(
17-
AuthenticatorAssertionRawResponse assertionResponse,
18-
AssertionOptions originalOptions,
19-
byte[] storedPublicKey,
20-
IReadOnlyList<byte[]> storedDevicePublicKeys,
21-
uint storedSignatureCounter,
22-
IsUserHandleOwnerOfCredentialIdAsync isUserHandleOwnerOfCredentialIdCallback,
23-
byte[]? requestTokenBindingId = null,
16+
Task<VerifyAssertionResult> MakeAssertionAsync(MakeAssertionParams makeAssertionParams,
2417
CancellationToken cancellationToken = default);
2518

26-
Task<RegisteredPublicKeyCredential> MakeNewCredentialAsync(
27-
AuthenticatorAttestationRawResponse attestationResponse,
28-
CredentialCreateOptions originalOptions,
29-
IsCredentialIdUniqueToUserAsyncDelegate isCredentialIdUniqueToUser,
30-
byte[]? requestTokenBindingId = null,
19+
Task<RegisteredPublicKeyCredential> MakeNewCredentialAsync(MakeNewCredentialParams makeNewCredentialParams,
3120
CancellationToken cancellationToken = default);
3221

3322
CredentialCreateOptions RequestNewCredential(

Src/Fido2/MakeAssertionParams.cs

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
5+
namespace Fido2NetLib;
6+
7+
/// <summary>
8+
/// Wraps the input for the MakeAssertion function
9+
/// </summary>
10+
public sealed class MakeAssertionParams
11+
{
12+
/// <summary>
13+
/// The assertion response from the authenticator.
14+
/// </summary>
15+
public required AuthenticatorAssertionRawResponse AssertionResponse { get; init; }
16+
17+
/// <summary>
18+
/// The original options that was sent to the client.
19+
/// </summary>
20+
public required AssertionOptions OriginalOptions { get; init; }
21+
22+
/// <summary>
23+
/// The stored credential public key.
24+
/// </summary>
25+
public required byte[] StoredPublicKey { get; init; }
26+
27+
/// <summary>
28+
/// The stored value of the signature counter.
29+
/// </summary>
30+
public required uint StoredSignatureCounter { get; init; }
31+
32+
/// <summary>
33+
/// The delegate used to validate that the user handle is indeed owned of the CredentialId.
34+
/// </summary>
35+
public required IsUserHandleOwnerOfCredentialIdAsync IsUserHandleOwnerOfCredentialIdCallback { get; init; }
36+
37+
/// <summary>
38+
/// The stored device public keys.
39+
/// </summary>
40+
public IReadOnlyList<byte[]> StoredDevicePublicKeys { get; init; } = Array.Empty<byte[]>();
41+
42+
/// <summary>
43+
/// DO NOT USE - Deprecated, but kept in code due to conformance testing tool.
44+
/// </summary>
45+
[EditorBrowsable(EditorBrowsableState.Never)]
46+
public byte[]? RequestTokenBindingId { get; init; }
47+
}

Src/Fido2/MakeNewCredentialParams.cs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System.ComponentModel;
2+
3+
namespace Fido2NetLib;
4+
5+
/// <summary>
6+
/// Wraps the input for the MakeNewCredential function
7+
/// </summary>
8+
public sealed class MakeNewCredentialParams
9+
{
10+
/// <summary>
11+
/// The attestation response from the authenticator.
12+
/// </summary>
13+
public required AuthenticatorAttestationRawResponse AttestationResponse { get; init; }
14+
15+
/// <summary>
16+
/// The original options that was sent to the client.
17+
/// </summary>
18+
public required CredentialCreateOptions OriginalOptions { get; init; }
19+
20+
/// <summary>
21+
/// The delegate used to validate that the CredentialID is unique to this user.
22+
/// </summary>
23+
public required IsCredentialIdUniqueToUserAsyncDelegate IsCredentialIdUniqueToUserCallback { get; init; }
24+
25+
/// <summary>
26+
/// DO NOT USE - Deprecated, but kept in code due to conformance testing tool
27+
/// </summary>
28+
[EditorBrowsable(EditorBrowsableState.Never)]
29+
public byte[]? RequestTokenBindingId { get; init; }
30+
}

Tests/Fido2.Tests/Attestation/Apple.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,12 @@ public async Task TestApplePublicKeyMismatch()
269269
Origins = new HashSet<string> { "https://www.passwordless.dev" },
270270
});
271271

272-
var credentialMakeResult = await lib.MakeNewCredentialAsync(attestationResponse, originalOptions, callback);
272+
var credentialMakeResult = await lib.MakeNewCredentialAsync(new MakeNewCredentialParams
273+
{
274+
AttestationResponse = attestationResponse,
275+
OriginalOptions = originalOptions,
276+
IsCredentialIdUniqueToUserCallback = callback
277+
});
273278
}
274279

275280
private string[] StackAllocSha256(ReadOnlySpan<byte> authData, ReadOnlySpan<byte> clientDataJson)

0 commit comments

Comments
 (0)