Skip to content

Commit 15e9108

Browse files
committed
Support authenticatorAttachment in PublicKeyCredential
1 parent 747bb78 commit 15e9108

File tree

5 files changed

+106
-3
lines changed

5 files changed

+106
-3
lines changed

webauthn-server-core/src/main/java/com/yubico/webauthn/AssertionResult.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.fasterxml.jackson.annotation.JsonProperty;
3030
import com.yubico.webauthn.data.AuthenticatorAssertionExtensionOutputs;
3131
import com.yubico.webauthn.data.AuthenticatorAssertionResponse;
32+
import com.yubico.webauthn.data.AuthenticatorAttachment;
3233
import com.yubico.webauthn.data.AuthenticatorData;
3334
import com.yubico.webauthn.data.ByteArray;
3435
import com.yubico.webauthn.data.ClientAssertionExtensionOutputs;
@@ -195,6 +196,19 @@ public boolean isBackedUp() {
195196
return credentialResponse.getResponse().getParsedAuthenticatorData().getFlags().BS;
196197
}
197198

199+
/**
200+
* The <a href="https://w3c.github.io/webauthn/#authenticator-attachment-modality">authenticator
201+
* attachment modality</a> in effect at the time the asserted credential was used.
202+
*
203+
* @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as
204+
* the standard matures.
205+
*/
206+
@Deprecated
207+
@JsonIgnore
208+
public Optional<AuthenticatorAttachment> getAuthenticatorAttachment() {
209+
return credentialResponse.getAuthenticatorAttachment();
210+
}
211+
198212
/**
199213
* The new <a href="https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#signcount">signature
200214
* count</a> of the credential used for the assertion.

webauthn-server-core/src/main/java/com/yubico/webauthn/RegistrationResult.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.yubico.webauthn.RelyingParty.RelyingPartyBuilder;
3232
import com.yubico.webauthn.attestation.AttestationTrustSource;
3333
import com.yubico.webauthn.data.AttestationType;
34+
import com.yubico.webauthn.data.AuthenticatorAttachment;
3435
import com.yubico.webauthn.data.AuthenticatorAttestationResponse;
3536
import com.yubico.webauthn.data.AuthenticatorRegistrationExtensionOutputs;
3637
import com.yubico.webauthn.data.ByteArray;
@@ -175,6 +176,19 @@ public boolean isBackedUp() {
175176
return credential.getResponse().getParsedAuthenticatorData().getFlags().BS;
176177
}
177178

179+
/**
180+
* The <a href="https://w3c.github.io/webauthn/#authenticator-attachment-modality">authenticator
181+
* attachment modality</a> in effect at the time the credential was created.
182+
*
183+
* @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as
184+
* the standard matures.
185+
*/
186+
@Deprecated
187+
@JsonIgnore
188+
public Optional<AuthenticatorAttachment> getAuthenticatorAttachment() {
189+
return credential.getAuthenticatorAttachment();
190+
}
191+
178192
/**
179193
* The signature count returned with the created credential.
180194
*

webauthn-server-core/src/main/java/com/yubico/webauthn/data/PublicKeyCredential.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
package com.yubico.webauthn.data;
2626

2727
import com.fasterxml.jackson.annotation.JsonCreator;
28-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
2928
import com.fasterxml.jackson.annotation.JsonProperty;
3029
import com.fasterxml.jackson.core.type.TypeReference;
3130
import com.yubico.internal.util.JacksonCodecs;
3231
import java.io.IOException;
32+
import java.util.Optional;
3333
import lombok.AllArgsConstructor;
3434
import lombok.Builder;
3535
import lombok.NonNull;
@@ -46,7 +46,6 @@
4646
*/
4747
@Value
4848
@Builder(toBuilder = true)
49-
@JsonIgnoreProperties({"authenticatorAttachment"})
5049
public class PublicKeyCredential<
5150
A extends AuthenticatorResponse, B extends ClientExtensionOutputs> {
5251

@@ -68,6 +67,8 @@ public class PublicKeyCredential<
6867
*/
6968
@NonNull private final A response;
7069

70+
private final AuthenticatorAttachment authenticatorAttachment;
71+
7172
/**
7273
* A map containing extension identifier → client extension output entries produced by the
7374
* extension’s client extension processing.
@@ -83,6 +84,7 @@ private PublicKeyCredential(
8384
@JsonProperty("id") ByteArray id,
8485
@JsonProperty("rawId") ByteArray rawId,
8586
@NonNull @JsonProperty("response") A response,
87+
@JsonProperty("authenticatorAttachment") AuthenticatorAttachment authenticatorAttachment,
8688
@NonNull @JsonProperty("clientExtensionResults") B clientExtensionResults,
8789
@NonNull @JsonProperty("type") PublicKeyCredentialType type) {
8890
if (id == null && rawId == null) {
@@ -95,16 +97,30 @@ private PublicKeyCredential(
9597

9698
this.id = id == null ? rawId : id;
9799
this.response = response;
100+
this.authenticatorAttachment = authenticatorAttachment;
98101
this.clientExtensionResults = clientExtensionResults;
99102
this.type = type;
100103
}
101104

102105
private PublicKeyCredential(
103106
ByteArray id,
104107
@NonNull A response,
108+
AuthenticatorAttachment authenticatorAttachment,
105109
@NonNull B clientExtensionResults,
106110
@NonNull PublicKeyCredentialType type) {
107-
this(id, null, response, clientExtensionResults, type);
111+
this(id, null, response, authenticatorAttachment, clientExtensionResults, type);
112+
}
113+
114+
/**
115+
* The <a href="https://w3c.github.io/webauthn/#authenticator-attachment-modality">authenticator
116+
* attachment modality</a> in effect at the time the credential was used.
117+
*
118+
* @deprecated EXPERIMENTAL: This feature is from a not yet mature standard; it could change as
119+
* the standard matures.
120+
*/
121+
@Deprecated
122+
public Optional<AuthenticatorAttachment> getAuthenticatorAttachment() {
123+
return Optional.ofNullable(authenticatorAttachment);
108124
}
109125

110126
public static <A extends AuthenticatorResponse, B extends ClientExtensionOutputs>

webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyAssertionSpec.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.upokecenter.cbor.CBORObject
3131
import com.yubico.internal.util.JacksonCodecs
3232
import com.yubico.webauthn.data.AssertionExtensionInputs
3333
import com.yubico.webauthn.data.AuthenticatorAssertionResponse
34+
import com.yubico.webauthn.data.AuthenticatorAttachment
3435
import com.yubico.webauthn.data.AuthenticatorDataFlags
3536
import com.yubico.webauthn.data.AuthenticatorTransport
3637
import com.yubico.webauthn.data.ByteArray
@@ -2592,6 +2593,36 @@ class RelyingPartyAssertionSpec
25922593
resultWithBeOnly.isBackedUp should be(false)
25932594
resultWithBackup.isBackedUp should be(true)
25942595
}
2596+
2597+
it(
2598+
"exposes getAuthenticatorAttachment() with the authenticatorAttachment value from the PublicKeyCredential."
2599+
) {
2600+
val pkcTemplate =
2601+
TestAuthenticator.createAssertion(
2602+
challenge =
2603+
request.getPublicKeyCredentialRequestOptions.getChallenge,
2604+
credentialKey = credentialKeypair,
2605+
credentialId = credential.getId,
2606+
)
2607+
2608+
forAll { authenticatorAttachment: Option[AuthenticatorAttachment] =>
2609+
val pkc = pkcTemplate.toBuilder
2610+
.authenticatorAttachment(authenticatorAttachment.orNull)
2611+
.build()
2612+
2613+
val result = rp.finishAssertion(
2614+
FinishAssertionOptions
2615+
.builder()
2616+
.request(request)
2617+
.response(pkc)
2618+
.build()
2619+
)
2620+
2621+
result.getAuthenticatorAttachment should equal(
2622+
pkc.getAuthenticatorAttachment
2623+
)
2624+
}
2625+
}
25952626
}
25962627
}
25972628
}

webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyRegistrationSpec.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import com.yubico.webauthn.attestation.AttestationTrustSource
4242
import com.yubico.webauthn.attestation.AttestationTrustSource.TrustRootsResult
4343
import com.yubico.webauthn.data.AttestationObject
4444
import com.yubico.webauthn.data.AttestationType
45+
import com.yubico.webauthn.data.AuthenticatorAttachment
4546
import com.yubico.webauthn.data.AuthenticatorAttestationResponse
4647
import com.yubico.webauthn.data.AuthenticatorData
4748
import com.yubico.webauthn.data.AuthenticatorDataFlags
@@ -4619,6 +4620,33 @@ class RelyingPartyRegistrationSpec
46194620
resultWithBeOnly.isBackedUp should be(false)
46204621
resultWithBackup.isBackedUp should be(true)
46214622
}
4623+
4624+
it(
4625+
"exposes getAuthenticatorAttachment() with the authenticatorAttachment value from the PublicKeyCredential."
4626+
) {
4627+
val (pkcTemplate, _, _) =
4628+
TestAuthenticator.createUnattestedCredential(challenge =
4629+
request.getChallenge
4630+
)
4631+
4632+
forAll { authenticatorAttachment: Option[AuthenticatorAttachment] =>
4633+
val pkc = pkcTemplate.toBuilder
4634+
.authenticatorAttachment(authenticatorAttachment.orNull)
4635+
.build()
4636+
4637+
val result = rp.finishRegistration(
4638+
FinishRegistrationOptions
4639+
.builder()
4640+
.request(request)
4641+
.response(pkc)
4642+
.build()
4643+
)
4644+
4645+
result.getAuthenticatorAttachment should equal(
4646+
pkc.getAuthenticatorAttachment
4647+
)
4648+
}
4649+
}
46224650
}
46234651
}
46244652

0 commit comments

Comments
 (0)