Skip to content

Commit 6871e19

Browse files
committed
Add shortcut parser functions to PublicKeyCredential
So users don't have to deal with these atrocious `TypeReference`s if they don't want to.
1 parent 17061e2 commit 6871e19

File tree

4 files changed

+115
-3
lines changed

4 files changed

+115
-3
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
New features:
44

55
* RSA keys are now supported.
6+
* New constructor functions `PublicKeyCredential.parseRegistrationResponseJson` and `.parseAssertionResponseJson`
7+
* So users don't have to deal with the `TypeReference`s imposed by the generics, unless they want to.
68

79
Bug fixes:
810

README

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ Get the response from the client:
146146
----------
147147
String responseJson = /* ... */;
148148
PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> pkc =
149-
jsonMapper.readValue(responseJson, new TypeReference<PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs>>(){});
149+
PublicKeyCredential.parseRegistrationResponseJson(responseJson);
150150
----------
151151

152152
Validate the response:
@@ -190,8 +190,7 @@ Validate the response:
190190
String responseJson = /* ... */;
191191

192192
PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> pkc =
193-
jsonMapper.readValue(responseJson, new TypeReference<PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>>() {
194-
});
193+
PublicKeyCredential.parseAssertionResponseJson(responseJson);
195194

196195
try {
197196
AssertionResult result = rp.finishAssertion(FinishAssertionOptions.builder()

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

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626

2727
import com.fasterxml.jackson.annotation.JsonCreator;
2828
import com.fasterxml.jackson.annotation.JsonProperty;
29+
import com.fasterxml.jackson.core.type.TypeReference;
30+
import com.yubico.internal.util.WebAuthnCodecs;
31+
import java.io.IOException;
2932
import lombok.AllArgsConstructor;
3033
import lombok.Builder;
3134
import lombok.NonNull;
@@ -126,4 +129,80 @@ public PublicKeyCredentialBuilder<A, B> clientExtensionResults(B clientExtension
126129

127130
}
128131

132+
/**
133+
* Parse a {@link PublicKeyCredential} object from JSON.
134+
*
135+
* <p>The <code>json</code> should be of the following format:</p>
136+
*
137+
* <pre>
138+
* {
139+
* "id": "(resp.id)",
140+
* "response": {
141+
* "attestationObject": "(Base64Url encoded resp.attestationObject)",
142+
* "clientDataJSON": "(Base64Url encoded resp.clientDataJSON)"
143+
* },
144+
* "clientExtensionResults": { (resp.getClientExtensionResults()) },
145+
* "type": "public-key"
146+
* }
147+
* </pre>
148+
*
149+
* <dl>
150+
* <dt>resp:</dt><dd>The <a href="https://www.w3.org/TR/webauthn-1/#iface-pkcredential">PublicKeyCredential</a> object returned from a registration ceremony.</dd>
151+
* <dt>id:</dt><dd>The string value of <code>resp.id</code></dd>
152+
* <dt>response.attestationObject:</dt><dd>The value of <code>resp.attestationObject</code>, Base64Url encoded as a string</dd>
153+
* <dt>response.clientDataJSON:</dt><dd>The value of <code>resp.clientDataJSON</code>, Base64Url encoded as a string</dd>
154+
* <dt>clientExtensionResults:</dt><dd>The return value of <code>resp.getClientExtensionResults()</code></dd>
155+
* <dt>type:</dt><dd>The literal string value <code>"public-key"</code></dd>
156+
* </dl>
157+
*
158+
* @param json a JSON string of the above format
159+
* @throws IOException if the <code>json</code> is invalid or cannot be decoded as a {@link PublicKeyCredential}
160+
*/
161+
public static PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> parseRegistrationResponseJson(String json) throws IOException {
162+
return WebAuthnCodecs.json().readValue(
163+
json,
164+
new TypeReference<PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs>>(){}
165+
);
166+
}
167+
168+
/**
169+
* Parse a {@link PublicKeyCredential} object from JSON.
170+
*
171+
* <p>The <code>json</code> should be of the following format:</p>
172+
*
173+
* <pre>
174+
* {
175+
* "id": "(resp.id)",
176+
* "response": {
177+
* "authenticatorData": "(Base64Url encoded resp.authenticatorData)",
178+
* "signature": "(Base64Url encoded resp.signature)",
179+
* "clientDataJSON": "(Base64Url encoded resp.clientDataJSON)",
180+
* "userHandle": "(null, undefined or Base64Url encoded resp.userHandle)"
181+
* },
182+
* "clientExtensionResults": { (resp.getClientExtensionResults()) },
183+
* "type": "public-key"
184+
* }
185+
* </pre>
186+
*
187+
* <dl>
188+
* <dt>resp:</dt><dd>The <a href="https://www.w3.org/TR/webauthn-1/#iface-pkcredential">PublicKeyCredential</a> object returned from an authentication ceremony.</dd>
189+
* <dt>id:</dt><dd>The string value of <code>resp.id</code></dd>
190+
* <dt>response.authenticatorData:</dt><dd>The value of <code>resp.authenticatorData</code>, Base64Url encoded as a string</dd>
191+
* <dt>response.signature:</dt><dd>The value of <code>resp.signature</code>, Base64Url encoded as a string</dd>
192+
* <dt>response.clientDataJSON:</dt><dd>The value of <code>resp.clientDataJSON</code>, Base64Url encoded as a string</dd>
193+
* <dt>response.userHandle:</dt><dd>The value of <code>resp.userHandle</code> Base64Url encoded as a string if present, otherwise <code>null</code> or <code>undefined</code></dd>
194+
* <dt>clientExtensionResults:</dt><dd>The return value of <code>resp.getClientExtensionResults()</code></dd>
195+
* <dt>type:</dt><dd>The literal string value <code>"public-key"</code></dd>
196+
* </dl>
197+
*
198+
* @param json a JSON string of the above format
199+
* @throws IOException if the <code>json</code> is invalid or cannot be decoded as a {@link PublicKeyCredential}
200+
*/
201+
public static PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> parseAssertionResponseJson(String json) throws IOException {
202+
return WebAuthnCodecs.json().readValue(
203+
json,
204+
new TypeReference<PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs>>(){}
205+
);
206+
}
207+
129208
}

webauthn-server-core/src/test/scala/com/yubico/webauthn/data/JsonIoSpec.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,36 @@ class JsonIoSpec extends FunSpec with Matchers with GeneratorDrivenPropertyCheck
124124
test(new TypeReference[UserVerificationRequirement]() {})
125125
}
126126

127+
describe("The class PublicKeyCredential") {
128+
it("has an alternative parseRegistrationResponseJson function as an alias.") {
129+
def test[A](tpe: TypeReference[A])(implicit a: Arbitrary[A]): Unit = {
130+
forAll { value: A =>
131+
val encoded: String = json.writeValueAsString(value)
132+
val decoded: A = json.readValue(encoded, tpe)
133+
val altDecoded = PublicKeyCredential.parseRegistrationResponseJson(encoded)
134+
val altRecoded: String = json.writeValueAsString(altDecoded)
135+
136+
altDecoded should equal (decoded)
137+
altRecoded should equal (encoded)
138+
}
139+
}
140+
test(new TypeReference[PublicKeyCredential[AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs]](){})
141+
}
142+
143+
it("has an alternative parseAuthenticationResponseJson function as an alias.") {
144+
def test[A](tpe: TypeReference[A])(implicit a: Arbitrary[A]): Unit = {
145+
forAll { value: A =>
146+
val encoded: String = json.writeValueAsString(value)
147+
val decoded: A = json.readValue(encoded, tpe)
148+
val altDecoded = PublicKeyCredential.parseAssertionResponseJson(encoded)
149+
val altRecoded: String = json.writeValueAsString(altDecoded)
150+
151+
altDecoded should equal (decoded)
152+
altRecoded should equal (encoded)
153+
}
154+
}
155+
test(new TypeReference[PublicKeyCredential[AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs]](){})
156+
}
157+
}
158+
127159
}

0 commit comments

Comments
 (0)