diff --git a/BlazorWasmDemo/Client/Shared/UserService.cs b/BlazorWasmDemo/Client/Shared/UserService.cs index fe39b5d7..018a23fb 100644 --- a/BlazorWasmDemo/Client/Shared/UserService.cs +++ b/BlazorWasmDemo/Client/Shared/UserService.cs @@ -105,7 +105,7 @@ public UserService(HttpClient httpClient, WebAuthn webAuthn) { Console.WriteLine(e); var errorMessage = e.Message; - if (options.ExcludeCredentials?.Any() ?? false) + if (options.ExcludeCredentials?.Count > 0) { errorMessage += " (You may have already registered this device)"; } diff --git a/BlazorWasmDemo/Server/Controllers/UserController.cs b/BlazorWasmDemo/Server/Controllers/UserController.cs index 387ef9c8..e34d91b7 100644 --- a/BlazorWasmDemo/Server/Controllers/UserController.cs +++ b/BlazorWasmDemo/Server/Controllers/UserController.cs @@ -83,7 +83,7 @@ public UserController(IFido2 fido2) }); // 2. Get user existing keys by username - var existingKeys = _demoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor); + var existingKeys = _demoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); // 3. Build authenticator selection var authenticatorSelection = AuthenticatorSelection.Default; diff --git a/Demo/Controller.cs b/Demo/Controller.cs index 07b068d5..103f50f9 100644 --- a/Demo/Controller.cs +++ b/Demo/Controller.cs @@ -59,7 +59,7 @@ private string FormatException(Exception e) }); // 2. Get user existing keys by username - var existingKeys = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor); + var existingKeys = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); // 3. Create options var authenticatorSelection = new AuthenticatorSelection diff --git a/Demo/TestController.cs b/Demo/TestController.cs index 24cb34c2..2d5e64f6 100644 --- a/Demo/TestController.cs +++ b/Demo/TestController.cs @@ -63,7 +63,7 @@ public JsonResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialParams }); // 2. Get user existing keys by username - var existingKeys = _demoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor); + var existingKeys = _demoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); //var exts = new AuthenticationExtensionsClientInputs() { Extensions = true, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, BiometricAuthenticatorPerformanceBounds = new AuthenticatorBiometricPerfBounds { FAR = float.MaxValue, FRR = float.MaxValue } }; var exts = new AuthenticationExtensionsClientInputs() { }; @@ -122,7 +122,7 @@ public IActionResult AssertionOptionsTest([FromBody] TEST_AssertionClientParams return NotFound("username was not registered"); // 2. Get registered credentials from database - var existingCredentials = _demoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor); + var existingCredentials = _demoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); var uv = assertionClientParams.UserVerification; if (null != assertionClientParams.authenticatorSelection) diff --git a/README.md b/README.md index a280450c..182f33a0 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ var user = DemoStorage.GetOrAddUser(username, () => new User }); // 2. Get user existing keys by username -var existingKeys = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor); +var existingKeys = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); // 3. Create options var options = _lib.RequestNewCredential(user, existingKeys, AuthenticatorSelection.Default, AttestationConveyancePreference.Parse(attType)); @@ -153,7 +153,7 @@ var user = DemoStorage.GetUser(username); if (user == null) return NotFound("username was not registered"); // 2. Get registered credentials from database -var existingCredentials = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor); +var existingCredentials = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); // 3. Create options var options = _lib.GetAssertionOptions( diff --git a/Src/Fido2.Models/AssertionOptions.cs b/Src/Fido2.Models/AssertionOptions.cs index cb6e5c5e..b5811a50 100644 --- a/Src/Fido2.Models/AssertionOptions.cs +++ b/Src/Fido2.Models/AssertionOptions.cs @@ -36,7 +36,7 @@ public class AssertionOptions : Fido2ResponseBase /// 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) /// [JsonPropertyName("allowCredentials")] - public IEnumerable AllowCredentials { get; set; } + public IReadOnlyList AllowCredentials { get; set; } = new List(); /// /// 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 @@ -51,7 +51,12 @@ public class AssertionOptions : Fido2ResponseBase [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public AuthenticationExtensionsClientInputs Extensions { get; set; } - public static AssertionOptions Create(Fido2Configuration config, byte[] challenge, IEnumerable allowedCredentials, UserVerificationRequirement? userVerification, AuthenticationExtensionsClientInputs extensions) + public static AssertionOptions Create( + Fido2Configuration config, + byte[] challenge, + IReadOnlyList allowedCredentials, + UserVerificationRequirement? userVerification, + AuthenticationExtensionsClientInputs extensions) { return new AssertionOptions() { diff --git a/Src/Fido2.Models/CredentialCreateOptions.cs b/Src/Fido2.Models/CredentialCreateOptions.cs index e9091487..775d70ea 100644 --- a/Src/Fido2.Models/CredentialCreateOptions.cs +++ b/Src/Fido2.Models/CredentialCreateOptions.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; @@ -62,7 +61,7 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase /// This member is intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account on a single authenticator.The client is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter. /// [JsonPropertyName("excludeCredentials")] - public IEnumerable ExcludeCredentials { get; set; } = Enumerable.Empty(); + public IReadOnlyList ExcludeCredentials { get; set; } = new List(); /// /// 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. @@ -71,7 +70,14 @@ public sealed class CredentialCreateOptions : Fido2ResponseBase [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public AuthenticationExtensionsClientInputs Extensions { get; set; } - public static CredentialCreateOptions Create(Fido2Configuration config, byte[] challenge, Fido2User user, AuthenticatorSelection authenticatorSelection, AttestationConveyancePreference attestationConveyancePreference, IEnumerable excludeCredentials, AuthenticationExtensionsClientInputs extensions) + public static CredentialCreateOptions Create( + Fido2Configuration config, + byte[] challenge, + Fido2User user, + AuthenticatorSelection authenticatorSelection, + AttestationConveyancePreference attestationConveyancePreference, + IReadOnlyList excludeCredentials, + AuthenticationExtensionsClientInputs extensions) { return new CredentialCreateOptions { @@ -97,7 +103,7 @@ public static CredentialCreateOptions Create(Fido2Configuration config, byte[] c }, AuthenticatorSelection = authenticatorSelection, Attestation = attestationConveyancePreference, - ExcludeCredentials = excludeCredentials ?? Enumerable.Empty(), + ExcludeCredentials = excludeCredentials ?? Array.Empty(), Extensions = extensions }; } diff --git a/Src/Fido2/Fido2.cs b/Src/Fido2/Fido2.cs index 61bc49ed..1296284e 100644 --- a/Src/Fido2/Fido2.cs +++ b/Src/Fido2/Fido2.cs @@ -30,7 +30,7 @@ public class Fido2 : IFido2 /// Recommended. This member is intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account on a single authenticator.The client is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter. public CredentialCreateOptions RequestNewCredential( Fido2User user, - IEnumerable excludeCredentials, + IReadOnlyList excludeCredentials, AuthenticationExtensionsClientInputs? extensions = null) { return RequestNewCredential(user, excludeCredentials, AuthenticatorSelection.Default, AttestationConveyancePreference.None, extensions); @@ -44,7 +44,7 @@ public class Fido2 : IFido2 /// Recommended. This member is intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account on a single authenticator.The client is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter. public CredentialCreateOptions RequestNewCredential( Fido2User user, - IEnumerable excludeCredentials, + IReadOnlyList excludeCredentials, AuthenticatorSelection authenticatorSelection, AttestationConveyancePreference attestationPreference, AuthenticationExtensionsClientInputs? extensions = null) @@ -84,7 +84,7 @@ public class Fido2 : IFido2 /// /// public AssertionOptions GetAssertionOptions( - IEnumerable allowedCredentials, + IReadOnlyList allowedCredentials, UserVerificationRequirement? userVerification, AuthenticationExtensionsClientInputs? extensions = null) { diff --git a/Src/Fido2/IFido2.cs b/Src/Fido2/IFido2.cs index bb3eda48..1a4d6a95 100644 --- a/Src/Fido2/IFido2.cs +++ b/Src/Fido2/IFido2.cs @@ -9,8 +9,8 @@ namespace Fido2NetLib; public interface IFido2 { AssertionOptions GetAssertionOptions( - IEnumerable allowedCredentials, - UserVerificationRequirement? userVerification, + IReadOnlyList allowedCredentials, + UserVerificationRequirement? userVerification, AuthenticationExtensionsClientInputs? extensions = null); Task MakeAssertionAsync( @@ -30,12 +30,12 @@ public interface IFido2 CredentialCreateOptions RequestNewCredential( Fido2User user, - IEnumerable excludeCredentials, + IReadOnlyList excludeCredentials, AuthenticationExtensionsClientInputs? extensions = null); CredentialCreateOptions RequestNewCredential( Fido2User user, - IEnumerable excludeCredentials, + IReadOnlyList excludeCredentials, AuthenticatorSelection authenticatorSelection, AttestationConveyancePreference attestationPreference, AuthenticationExtensionsClientInputs? extensions = null);