Skip to content

Commit 5e48c77

Browse files
committed
Closes #638. Make sure residentKey services roundtrip
1 parent 2451de1 commit 5e48c77

File tree

2 files changed

+56
-5
lines changed

2 files changed

+56
-5
lines changed

Src/Fido2.Models/CredentialCreateOptions.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ public static CredentialCreateOptions Create(
126126
AttestationConveyancePreference attestationConveyancePreference,
127127
IReadOnlyList<PublicKeyCredentialDescriptor> excludeCredentials,
128128
AuthenticationExtensionsClientInputs? extensions,
129-
IReadOnlyList<PubKeyCredParam> pubKeyCredParams)
130-
129+
IReadOnlyList<PubKeyCredParam> pubKeyCredParams)
130+
131131
{
132132
return new CredentialCreateOptions
133133
{
@@ -184,8 +184,8 @@ public sealed class PubKeyCredParam(
184184
public static readonly PubKeyCredParam PS384 = new(COSE.Algorithm.PS384);
185185
public static readonly PubKeyCredParam PS512 = new(COSE.Algorithm.PS512);
186186
public static readonly PubKeyCredParam Ed25519 = new(COSE.Algorithm.EdDSA);
187-
public static readonly PubKeyCredParam RS1 = new(COSE.Algorithm.RS1);
188-
187+
public static readonly PubKeyCredParam RS1 = new(COSE.Algorithm.RS1);
188+
189189
/// <summary>
190190
/// The default algorithms supported by the library
191191
/// </summary>
@@ -283,7 +283,14 @@ public bool RequireResidentKey
283283
set
284284
{
285285
_requireResidentKey = value;
286-
_residentKey = value ? ResidentKeyRequirement.Required : ResidentKeyRequirement.Discouraged;
286+
if (value)
287+
{
288+
_residentKey = ResidentKeyRequirement.Required;
289+
}
290+
else if (_residentKey is not ResidentKeyRequirement.Preferred)
291+
{
292+
_residentKey = ResidentKeyRequirement.Discouraged;
293+
}
287294
}
288295
}
289296

Tests/Fido2.Tests/Fido2Tests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,50 @@ public void TestStringIsSerializable()
417417
Assert.Equal(z1, z2);
418418
}
419419

420+
[Fact]
421+
public void AuthenticatorSelection_ResidentKeyPreferred_SurvivesJsonRoundTrip()
422+
{
423+
// Arrange: Create AuthenticatorSelection with ResidentKey = Preferred
424+
var original = new AuthenticatorSelection
425+
{
426+
ResidentKey = ResidentKeyRequirement.Preferred,
427+
UserVerification = UserVerificationRequirement.Preferred
428+
};
429+
430+
// Act: Serialize to JSON and deserialize back
431+
var json = JsonSerializer.Serialize(original);
432+
var deserialized = JsonSerializer.Deserialize<AuthenticatorSelection>(json);
433+
434+
// Assert: ResidentKey should still be Preferred after round-trip
435+
Assert.Equal(ResidentKeyRequirement.Preferred, deserialized.ResidentKey);
436+
}
437+
438+
[Fact]
439+
public void CredentialCreateOptions_ResidentKeyPreferred_SurvivesJsonRoundTrip()
440+
{
441+
// Arrange: This JSON has residentKey: "preferred" which should be preserved
442+
const string json = """
443+
{
444+
"rp": { "id": "some.rp.id", "name": "Some name" },
445+
"user": { "name": "someuserid", "id": "NjVmZGNiOTJiZjQyZjZmZDE0YzViODVk", "displayName": "The User 1234" },
446+
"challenge": "kauVQPwQtf4BlhOFObDfTQ",
447+
"pubKeyCredParams": [ { "type": "public-key", "alg": -7 }, { "type": "public-key", "alg": -257 } ],
448+
"timeout": 60000,
449+
"attestation": "none",
450+
"attestationFormats": [],
451+
"authenticatorSelection": { "residentKey": "preferred", "requireResidentKey": false, "userVerification": "preferred" },
452+
"hints": [],
453+
"excludeCredentials": []
454+
}
455+
""";
456+
457+
// Act: Deserialize the JSON
458+
var options = CredentialCreateOptions.FromJson(json);
459+
460+
// Assert: ResidentKey should be Preferred, not Discouraged
461+
Assert.Equal(ResidentKeyRequirement.Preferred, options.AuthenticatorSelection.ResidentKey);
462+
}
463+
420464
[Fact]
421465
public async Task TestFido2AssertionAsync()
422466
{

0 commit comments

Comments
 (0)