From 37f32c3a74e6147394f4c08dc2f480a5e74f655d Mon Sep 17 00:00:00 2001 From: Dennis Fokin Date: Thu, 13 Jun 2024 14:40:38 +0200 Subject: [PATCH 1/4] Added credProps.authenticatorDisplayName --- NEWS | 3 ++ .../yubico/webauthn/RegistrationResult.java | 36 ++++++++++----- .../com/yubico/webauthn/data/Extensions.java | 27 ++++++++++- .../RelyingPartyRegistrationSpec.scala | 45 +++++++++++++++++++ .../com/yubico/webauthn/data/Generators.scala | 10 ++++- 5 files changed, 107 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index 39f984f47..d233009f3 100644 --- a/NEWS +++ b/NEWS @@ -51,6 +51,9 @@ New features: * (Experimental) Added property `RegisteredCredential.transports`. ** NOTE: Experimental features may receive breaking changes without a major version increase. +* (Experimental) Added property `credProps.authenticatorDisplayName`. + ** NOTE: Experimental features may receive breaking changes without a major + version increase. == Version 2.5.2 == diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java index 499003730..f3f3ece18 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java @@ -30,17 +30,7 @@ import com.yubico.internal.util.CertificateParser; import com.yubico.webauthn.RelyingParty.RelyingPartyBuilder; import com.yubico.webauthn.attestation.AttestationTrustSource; -import com.yubico.webauthn.data.AttestationType; -import com.yubico.webauthn.data.AuthenticatorAttachment; -import com.yubico.webauthn.data.AuthenticatorAttestationResponse; -import com.yubico.webauthn.data.AuthenticatorData; -import com.yubico.webauthn.data.AuthenticatorDataFlags; -import com.yubico.webauthn.data.AuthenticatorRegistrationExtensionOutputs; -import com.yubico.webauthn.data.AuthenticatorResponse; -import com.yubico.webauthn.data.ByteArray; -import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs; -import com.yubico.webauthn.data.PublicKeyCredential; -import com.yubico.webauthn.data.PublicKeyCredentialDescriptor; +import com.yubico.webauthn.data.*; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; @@ -367,6 +357,30 @@ public Optional isDiscoverable() { .flatMap(credProps -> credProps.getRk()); } + /** + * Retrieve a suitable nickname for this credential, if one is available. + * + *

This returns the authenticatorDisplayName output from the + * credProps extension. + * + * @return A user-chosen or vendor-default display name for the credential, if available. + * Otherwise empty. + * @see §10.1.3. + * Credential Properties Extension (credProps), "authenticatorDisplayName" output + * @see Extensions.CredentialProperties.CredentialPropertiesOutput#getAuthenticatorDisplayName() + * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as + * the standard matures. + */ + @JsonIgnore + @Deprecated + public Optional getAuthenticatorDisplayName() { + return getClientExtensionOutputs() + .flatMap(outputs -> outputs.getCredProps()) + .flatMap(credProps -> credProps.getAuthenticatorDisplayName()); + } + /** * The attestation diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java index d25d0f901..2d066cfc7 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonValue; import com.upokecenter.cbor.CBORObject; import com.upokecenter.cbor.CBORType; +import com.yubico.webauthn.RegistrationResult; import com.yubico.webauthn.StartRegistrationOptions; import com.yubico.webauthn.extension.uvm.KeyProtectionType; import com.yubico.webauthn.extension.uvm.MatcherProtectionType; @@ -71,9 +72,15 @@ public static class CredentialPropertiesOutput { @JsonProperty("rk") private final Boolean rk; + @JsonProperty("authenticatorDisplayName") + private final String authenticatorDisplayName; + @JsonCreator - private CredentialPropertiesOutput(@JsonProperty("rk") Boolean rk) { + private CredentialPropertiesOutput( + @JsonProperty("rk") Boolean rk, + @JsonProperty("authenticatorDisplayName") String authenticatorDisplayName) { this.rk = rk; + this.authenticatorDisplayName = authenticatorDisplayName; } /** @@ -105,6 +112,24 @@ private CredentialPropertiesOutput(@JsonProperty("rk") Boolean rk) { public Optional getRk() { return Optional.ofNullable(rk); } + + /** + * This OPTIONAL property is a human-palatable description of the credential's managing + * authenticator, chosen by the user. + * + *

If the RP includes an [$credential record/authenticatorDisplayName$] + * [=struct/item=] in [=credential records=], the [=[RP]=] MAY offer this value, if present, + * as a default value for the [$credential record/authenticatorDisplayName$] of + * the new [=credential record=]. + * + * @see RegistrationResult#getAuthenticatorDisplayName() + * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change + * as the standard matures. + */ + @Deprecated + public Optional getAuthenticatorDisplayName() { + return Optional.ofNullable(authenticatorDisplayName); + } } } diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyRegistrationSpec.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyRegistrationSpec.scala index 4f16eb1fd..49ee87a4b 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyRegistrationSpec.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyRegistrationSpec.scala @@ -4289,6 +4289,51 @@ class RelyingPartyRegistrationSpec } } + describe("expose the credProps.authenticatorDisplayName extension output as RegistrationResult.getAuthenticatorDisplayName()") { + val testDataBase = RegistrationTestData.Packed.BasicAttestation + val testData = testDataBase.copy(requestedExtensions = + testDataBase.request.getExtensions.toBuilder.credProps().build() + ) + + it("""when set to "hej".""") { + val result = rp.finishRegistration( + FinishRegistrationOptions + .builder() + .request(testData.request) + .response( + testData.response.toBuilder + .clientExtensionResults( + ClientRegistrationExtensionOutputs + .builder() + .credProps( + CredentialPropertiesOutput + .builder() + .authenticatorDisplayName("hej") + .build() + ) + .build() + ) + .build() + ) + .build() + ) + + result.getAuthenticatorDisplayName.toScala should equal(Some("hej")) + } + + it("when not available.") { + val result = rp.finishRegistration( + FinishRegistrationOptions + .builder() + .request(testData.request) + .response(testData.response) + .build() + ) + + result.getAuthenticatorDisplayName.toScala should equal(None) + } + } + describe("support the largeBlob extension") { it("being enabled at registration time.") { val testData = RegistrationTestData.Packed.BasicAttestation diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/Generators.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/Generators.scala index 2a7ce9df3..e1a32f6e6 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/Generators.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/Generators.scala @@ -867,8 +867,14 @@ object Generators { object CredProps { def credentialPropertiesOutput: Gen[CredentialPropertiesOutput] = for { - rk <- arbitrary[Boolean] - } yield CredentialPropertiesOutput.builder().rk(rk).build() + rk <- arbitrary[Option[Boolean]] + authenticatorDisplayName <- arbitrary[Option[String]] + } yield { + val b = CredentialPropertiesOutput.builder() + rk.foreach(b.rk(_)) + authenticatorDisplayName.foreach(b.authenticatorDisplayName) + b.build() + } } object LargeBlob { From 4b3bdd836decb7c67d89b783ead8c1bf6a23ef3d Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 11 Jul 2024 14:13:21 +0200 Subject: [PATCH 2/4] Expand wildcard import --- .../com/yubico/webauthn/RegistrationResult.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java index f3f3ece18..b31fe5b74 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java @@ -30,7 +30,18 @@ import com.yubico.internal.util.CertificateParser; import com.yubico.webauthn.RelyingParty.RelyingPartyBuilder; import com.yubico.webauthn.attestation.AttestationTrustSource; -import com.yubico.webauthn.data.*; +import com.yubico.webauthn.data.AttestationType; +import com.yubico.webauthn.data.AuthenticatorAttachment; +import com.yubico.webauthn.data.AuthenticatorAttestationResponse; +import com.yubico.webauthn.data.AuthenticatorData; +import com.yubico.webauthn.data.AuthenticatorDataFlags; +import com.yubico.webauthn.data.AuthenticatorRegistrationExtensionOutputs; +import com.yubico.webauthn.data.AuthenticatorResponse; +import com.yubico.webauthn.data.ByteArray; +import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs; +import com.yubico.webauthn.data.Extensions; +import com.yubico.webauthn.data.PublicKeyCredential; +import com.yubico.webauthn.data.PublicKeyCredentialDescriptor; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; From 02a10f6387fc478b76dba6a20ad315a75dee4c1b Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 11 Jul 2024 14:34:44 +0200 Subject: [PATCH 3/4] Tweak JavaDoc of authenticatorDisplayName --- .../com/yubico/webauthn/RegistrationResult.java | 7 ++++--- .../com/yubico/webauthn/data/Extensions.java | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java index b31fe5b74..8b5b75f40 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java @@ -372,14 +372,15 @@ public Optional isDiscoverable() { * Retrieve a suitable nickname for this credential, if one is available. * *

This returns the authenticatorDisplayName output from the + * href="https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension"> * credProps extension. * * @return A user-chosen or vendor-default display name for the credential, if available. * Otherwise empty. * @see §10.1.3. - * Credential Properties Extension (credProps), "authenticatorDisplayName" output + * href="https://w3c.github.io/webauthn/#dom-credentialpropertiesoutput-authenticatordisplayname"> + * authenticatorDisplayName in §10.1.3. Credential Properties Extension + * (credProps) * @see Extensions.CredentialProperties.CredentialPropertiesOutput#getAuthenticatorDisplayName() * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as * the standard matures. diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java index 2d066cfc7..6052e5b98 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java @@ -117,11 +117,19 @@ public Optional getRk() { * This OPTIONAL property is a human-palatable description of the credential's managing * authenticator, chosen by the user. * - *

If the RP includes an [$credential record/authenticatorDisplayName$] - * [=struct/item=] in [=credential records=], the [=[RP]=] MAY offer this value, if present, - * as a default value for the [$credential record/authenticatorDisplayName$] of - * the new [=credential record=]. + *

If the application supports setting "nicknames" for registered credentials, then this + * value may be a suitable default value for such a nickname. * + *

In an authentication ceremony, if this value is different from the stored nickname, then + * the application may want to offer the user to update the stored nickname to match this + * value. + * + * @return A user-chosen or vendor-default display name for the credential, if available. + * Otherwise empty. + * @see + * authenticatorDisplayName in §10.1.3. Credential Properties Extension + * (credProps) * @see RegistrationResult#getAuthenticatorDisplayName() * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change * as the standard matures. From a1a3e2f4062d776243f631174448859175142ef3 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 11 Jul 2024 15:31:48 +0200 Subject: [PATCH 4/4] Add credProps and authenticatorDisplayName to assertion extension outputs --- NEWS | 1 + .../com/yubico/webauthn/AssertionResult.java | 30 +++++++++++ .../yubico/webauthn/AssertionResultV2.java | 30 +++++++++++ .../yubico/webauthn/RegistrationResult.java | 2 + .../data/ClientAssertionExtensionOutputs.java | 26 ++++++++++ .../com/yubico/webauthn/data/Extensions.java | 4 ++ .../webauthn/RelyingPartyAssertionSpec.scala | 50 +++++++++++++++++++ .../RelyingPartyV2AssertionSpec.scala | 50 +++++++++++++++++++ 8 files changed, 193 insertions(+) diff --git a/NEWS b/NEWS index d233009f3..677142541 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,7 @@ New features: * (Experimental) Added property `credProps.authenticatorDisplayName`. ** NOTE: Experimental features may receive breaking changes without a major version increase. +* (Experimental) Added `credProps` extension to assertion extension outputs. == Version 2.5.2 == diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java index 5763af7af..50ec81975 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java @@ -35,6 +35,7 @@ import com.yubico.webauthn.data.AuthenticatorResponse; import com.yubico.webauthn.data.ByteArray; import com.yubico.webauthn.data.ClientAssertionExtensionOutputs; +import com.yubico.webauthn.data.Extensions; import com.yubico.webauthn.data.PublicKeyCredential; import com.yubico.webauthn.data.PublicKeyCredentialRequestOptions; import com.yubico.webauthn.data.UserIdentity; @@ -281,4 +282,33 @@ public Optional getAuthenticatorExtensio return AuthenticatorAssertionExtensionOutputs.fromAuthenticatorData( credentialResponse.getResponse().getParsedAuthenticatorData()); } + + /** + * Retrieve a suitable nickname for this credential, if one is available. This MAY differ from + * {@link RegistrationResult#getAuthenticatorDisplayName() the value returned during + * registration}, if any. In that case the application may want to offer the user to update the + * previously stored value, if any. + * + *

This returns the authenticatorDisplayName output from the + * credProps extension. + * + * @return A user-chosen or vendor-default display name for the credential, if available. + * Otherwise empty. + * @see + * authenticatorDisplayName in §10.1.3. Credential Properties Extension + * (credProps) + * @see RegistrationResult#getAuthenticatorDisplayName() + * @see Extensions.CredentialProperties.CredentialPropertiesOutput#getAuthenticatorDisplayName() + * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as + * the standard matures. + */ + @JsonIgnore + @Deprecated + public Optional getAuthenticatorDisplayName() { + return getClientExtensionOutputs() + .flatMap(outputs -> outputs.getCredProps()) + .flatMap(credProps -> credProps.getAuthenticatorDisplayName()); + } } diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResultV2.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResultV2.java index 5b027ffbc..27df1a515 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResultV2.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResultV2.java @@ -35,6 +35,7 @@ import com.yubico.webauthn.data.AuthenticatorResponse; import com.yubico.webauthn.data.ByteArray; import com.yubico.webauthn.data.ClientAssertionExtensionOutputs; +import com.yubico.webauthn.data.Extensions; import com.yubico.webauthn.data.PublicKeyCredential; import java.util.Optional; import lombok.AccessLevel; @@ -243,4 +244,33 @@ public Optional getAuthenticatorExtensio return AuthenticatorAssertionExtensionOutputs.fromAuthenticatorData( credentialResponse.getResponse().getParsedAuthenticatorData()); } + + /** + * Retrieve a suitable nickname for this credential, if one is available. This MAY differ from + * {@link RegistrationResult#getAuthenticatorDisplayName() the value returned during + * registration}, if any. In that case the application may want to offer the user to update the + * previously stored value, if any. + * + *

This returns the authenticatorDisplayName output from the + * credProps extension. + * + * @return A user-chosen or vendor-default display name for the credential, if available. + * Otherwise empty. + * @see + * authenticatorDisplayName in §10.1.3. Credential Properties Extension + * (credProps) + * @see RegistrationResult#getAuthenticatorDisplayName() + * @see Extensions.CredentialProperties.CredentialPropertiesOutput#getAuthenticatorDisplayName() + * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as + * the standard matures. + */ + @JsonIgnore + @Deprecated + public Optional getAuthenticatorDisplayName() { + return getClientExtensionOutputs() + .flatMap(outputs -> outputs.getCredProps()) + .flatMap(credProps -> credProps.getAuthenticatorDisplayName()); + } } diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java index 8b5b75f40..c1b8b9c66 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java @@ -381,6 +381,8 @@ public Optional isDiscoverable() { * href="https://w3c.github.io/webauthn/#dom-credentialpropertiesoutput-authenticatordisplayname"> * authenticatorDisplayName in §10.1.3. Credential Properties Extension * (credProps) + * @see AssertionResult#getAuthenticatorDisplayName() + * @see AssertionResultV2#getAuthenticatorDisplayName() * @see Extensions.CredentialProperties.CredentialPropertiesOutput#getAuthenticatorDisplayName() * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as * the standard matures. diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java index 3c6579d66..81c9af07d 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/ClientAssertionExtensionOutputs.java @@ -64,13 +64,18 @@ public class ClientAssertionExtensionOutputs implements ClientExtensionOutputs { */ private final Boolean appid; + private final Extensions.CredentialProperties.CredentialPropertiesOutput credProps; + private final Extensions.LargeBlob.LargeBlobAuthenticationOutput largeBlob; @JsonCreator private ClientAssertionExtensionOutputs( @JsonProperty("appid") Boolean appid, + @JsonProperty("credProps") + Extensions.CredentialProperties.CredentialPropertiesOutput credProps, @JsonProperty("largeBlob") Extensions.LargeBlob.LargeBlobAuthenticationOutput largeBlob) { this.appid = appid; + this.credProps = credProps; this.largeBlob = largeBlob; } @@ -81,6 +86,9 @@ public Set getExtensionIds() { if (appid != null) { ids.add(Extensions.Appid.EXTENSION_ID); } + if (credProps != null) { + ids.add(Extensions.CredentialProperties.EXTENSION_ID); + } if (largeBlob != null) { ids.add(Extensions.LargeBlob.EXTENSION_ID); } @@ -100,6 +108,24 @@ public Optional getAppid() { return Optional.ofNullable(appid); } + /** + * The extension output for the Credential Properties Extension (credProps), if any. + * + *

This value MAY be present but have all members empty if the extension was successfully + * processed but no credential properties could be determined. + * + * @see com.yubico.webauthn.data.Extensions.CredentialProperties.CredentialPropertiesOutput + * @see §10.4. + * Credential Properties Extension (credProps) + * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as + * the standard matures. + */ + @Deprecated + public Optional getCredProps() { + return Optional.ofNullable(credProps); + } + /** * The extension output for the Large blob diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java index 6052e5b98..0f762fb1f 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/Extensions.java @@ -6,6 +6,8 @@ import com.fasterxml.jackson.annotation.JsonValue; import com.upokecenter.cbor.CBORObject; import com.upokecenter.cbor.CBORType; +import com.yubico.webauthn.AssertionResult; +import com.yubico.webauthn.AssertionResultV2; import com.yubico.webauthn.RegistrationResult; import com.yubico.webauthn.StartRegistrationOptions; import com.yubico.webauthn.extension.uvm.KeyProtectionType; @@ -131,6 +133,8 @@ public Optional getRk() { * authenticatorDisplayName in §10.1.3. Credential Properties Extension * (credProps) * @see RegistrationResult#getAuthenticatorDisplayName() + * @see AssertionResult#getAuthenticatorDisplayName() + * @see AssertionResultV2#getAuthenticatorDisplayName() * @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change * as the standard matures. */ diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala index 6d4c711f2..ef809d116 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala @@ -38,6 +38,7 @@ import com.yubico.webauthn.data.AuthenticatorTransport import com.yubico.webauthn.data.ByteArray import com.yubico.webauthn.data.ClientAssertionExtensionOutputs import com.yubico.webauthn.data.CollectedClientData +import com.yubico.webauthn.data.Extensions.CredentialProperties.CredentialPropertiesOutput import com.yubico.webauthn.data.Extensions.LargeBlob.LargeBlobAuthenticationInput import com.yubico.webauthn.data.Extensions.LargeBlob.LargeBlobAuthenticationOutput import com.yubico.webauthn.data.Extensions.Uvm.UvmEntry @@ -2845,6 +2846,55 @@ class RelyingPartyAssertionSpec ) } } + + describe("exposes the credProps.authenticatorDisplayName extension output as getAuthenticatorDisplayName()") { + val pkcTemplate = + TestAuthenticator.createAssertion( + challenge = + request.getPublicKeyCredentialRequestOptions.getChallenge, + credentialKey = credentialKeypair, + credentialId = credential.getId, + ) + + it("""when set to "hej".""") { + val pkc = pkcTemplate.toBuilder + .clientExtensionResults( + pkcTemplate.getClientExtensionResults.toBuilder + .credProps( + CredentialPropertiesOutput + .builder() + .authenticatorDisplayName("hej") + .build() + ) + .build() + ) + .build() + val result = rp.finishAssertion( + FinishAssertionOptions + .builder() + .request(request) + .response(pkc) + .build() + ) + + result.getAuthenticatorDisplayName.toScala should equal( + Some("hej") + ) + } + + it("when not available.") { + val pkc = pkcTemplate + val result = rp.finishAssertion( + FinishAssertionOptions + .builder() + .request(request) + .response(pkc) + .build() + ) + + result.getAuthenticatorDisplayName.toScala should equal(None) + } + } } } } diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyV2AssertionSpec.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyV2AssertionSpec.scala index 402f2f1d7..794db38fb 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyV2AssertionSpec.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyV2AssertionSpec.scala @@ -38,6 +38,7 @@ import com.yubico.webauthn.data.AuthenticatorTransport import com.yubico.webauthn.data.ByteArray import com.yubico.webauthn.data.ClientAssertionExtensionOutputs import com.yubico.webauthn.data.CollectedClientData +import com.yubico.webauthn.data.Extensions.CredentialProperties.CredentialPropertiesOutput import com.yubico.webauthn.data.Extensions.LargeBlob.LargeBlobAuthenticationInput import com.yubico.webauthn.data.Extensions.LargeBlob.LargeBlobAuthenticationOutput import com.yubico.webauthn.data.Extensions.Uvm.UvmEntry @@ -2920,6 +2921,55 @@ class RelyingPartyV2AssertionSpec ) } } + + describe("exposes the credProps.authenticatorDisplayName extension output as getAuthenticatorDisplayName()") { + val pkcTemplate = + TestAuthenticator.createAssertion( + challenge = + request.getPublicKeyCredentialRequestOptions.getChallenge, + credentialKey = credentialKeypair, + credentialId = credential.getId, + ) + + it("""when set to "hej".""") { + val pkc = pkcTemplate.toBuilder + .clientExtensionResults( + pkcTemplate.getClientExtensionResults.toBuilder + .credProps( + CredentialPropertiesOutput + .builder() + .authenticatorDisplayName("hej") + .build() + ) + .build() + ) + .build() + val result = rp.finishAssertion( + FinishAssertionOptions + .builder() + .request(request) + .response(pkc) + .build() + ) + + result.getAuthenticatorDisplayName.toScala should equal( + Some("hej") + ) + } + + it("when not available.") { + val pkc = pkcTemplate + val result = rp.finishAssertion( + FinishAssertionOptions + .builder() + .request(request) + .response(pkc) + .build() + ) + + result.getAuthenticatorDisplayName.toScala should equal(None) + } + } } } }