Skip to content

Commit ec9a900

Browse files
committed
Test that PublicKeyCredential only requires at least one of id and rawId
1 parent 86da128 commit ec9a900

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

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

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,21 @@ import com.fasterxml.jackson.core.`type`.TypeReference
2929
import com.fasterxml.jackson.databind.DeserializationFeature
3030
import com.fasterxml.jackson.databind.ObjectMapper
3131
import com.fasterxml.jackson.databind.SerializationFeature
32+
import com.fasterxml.jackson.databind.exc.ValueInstantiationException
33+
import com.fasterxml.jackson.databind.node.ObjectNode
34+
import com.fasterxml.jackson.databind.node.TextNode
3235
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module
3336
import com.yubico.webauthn.AssertionRequest
3437
import com.yubico.webauthn.AssertionResult
3538
import com.yubico.webauthn.Generators._
39+
import com.yubico.webauthn.RegisteredCredential
3640
import com.yubico.webauthn.RegistrationResult
3741
import com.yubico.webauthn.attestation.Attestation
3842
import com.yubico.webauthn.attestation.Generators._
3943
import com.yubico.webauthn.attestation.Transport
4044
import com.yubico.webauthn.data.Generators._
4145
import com.yubico.webauthn.extension.appid.AppId
4246
import com.yubico.webauthn.extension.appid.Generators._
43-
import com.yubico.webauthn.RegisteredCredential
4447
import org.junit.runner.RunWith
4548
import org.scalacheck.Arbitrary
4649
import org.scalatest.FunSpec
@@ -161,6 +164,106 @@ class JsonIoSpec extends FunSpec with Matchers with ScalaCheckDrivenPropertyChec
161164
}
162165
test(new TypeReference[PublicKeyCredential[AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs]](){})
163166
}
167+
168+
it("allows rawId to be present without id.") {
169+
def test[P <: PublicKeyCredential[_, _]](tpe: TypeReference[P])(implicit a: Arbitrary[P]): Unit = {
170+
forAll { value: P =>
171+
val encoded: String = json.writeValueAsString(value)
172+
val decoded = json.readTree(encoded)
173+
decoded.asInstanceOf[ObjectNode]
174+
.set[ObjectNode]("rawId", new TextNode(value.getId.getBase64Url))
175+
.remove("id")
176+
val reencoded = json.writeValueAsString(decoded)
177+
val restored: P = json.readValue(reencoded, tpe)
178+
179+
restored.getId should equal (value.getId)
180+
restored should equal (value)
181+
}
182+
}
183+
test(new TypeReference[PublicKeyCredential[AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs]](){})
184+
test(new TypeReference[PublicKeyCredential[AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs]](){})
185+
}
186+
187+
it("allows id to be present without rawId.") {
188+
def test[P <: PublicKeyCredential[_, _]](tpe: TypeReference[P])(implicit a: Arbitrary[P]): Unit = {
189+
forAll { value: P =>
190+
val encoded: String = json.writeValueAsString(value)
191+
val decoded = json.readTree(encoded)
192+
decoded.asInstanceOf[ObjectNode]
193+
.set[ObjectNode]("id", new TextNode(value.getId.getBase64Url))
194+
.remove("rawId")
195+
val reencoded = json.writeValueAsString(decoded)
196+
val restored: P = json.readValue(reencoded, tpe)
197+
198+
restored should equal (value)
199+
}
200+
}
201+
test(new TypeReference[PublicKeyCredential[AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs]](){})
202+
test(new TypeReference[PublicKeyCredential[AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs]](){})
203+
}
204+
205+
it("allows both id and rawId to be present if equal.") {
206+
def test[P <: PublicKeyCredential[_, _]](tpe: TypeReference[P])(implicit a: Arbitrary[P]): Unit = {
207+
forAll { value: P =>
208+
val encoded: String = json.writeValueAsString(value)
209+
val decoded = json.readTree(encoded)
210+
decoded.asInstanceOf[ObjectNode].set("id", new TextNode(value.getId.getBase64Url))
211+
decoded.asInstanceOf[ObjectNode].set("rawId", new TextNode(value.getId.getBase64Url))
212+
val reencoded = json.writeValueAsString(decoded)
213+
val restored: P = json.readValue(reencoded, tpe)
214+
215+
restored should equal (value)
216+
}
217+
}
218+
test(new TypeReference[PublicKeyCredential[AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs]](){})
219+
test(new TypeReference[PublicKeyCredential[AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs]](){})
220+
}
221+
222+
it("does not allow both id and rawId to be absent.") {
223+
def test[P <: PublicKeyCredential[_, _]](tpe: TypeReference[P])(implicit a: Arbitrary[P]): Unit = {
224+
forAll { value: P =>
225+
val encoded: String = json.writeValueAsString(value)
226+
val decoded = json.readTree(encoded).asInstanceOf[ObjectNode]
227+
decoded.remove("id")
228+
decoded.remove("rawId")
229+
val reencoded = json.writeValueAsString(decoded)
230+
231+
an [ValueInstantiationException] should be thrownBy {
232+
json.readValue(reencoded, tpe)
233+
}
234+
}
235+
}
236+
237+
test(new TypeReference[PublicKeyCredential[AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs]](){})
238+
test(new TypeReference[PublicKeyCredential[AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs]](){})
239+
}
240+
241+
it("does not allow both id and rawId to be present and not equal.") {
242+
def test[P <: PublicKeyCredential[_, _]](tpe: TypeReference[P])(implicit a: Arbitrary[P]): Unit = {
243+
forAll { value: P =>
244+
val modId = new ByteArray(
245+
if (value.getId.getBytes.isEmpty)
246+
Array(0)
247+
else
248+
value.getId.getBytes.updated(0, (value.getId.getBytes()(0) + 1 % 127).byteValue)
249+
)
250+
251+
val encoded: String = json.writeValueAsString(value)
252+
val decoded = json.readTree(encoded)
253+
decoded.asInstanceOf[ObjectNode]
254+
.set[ObjectNode]("id", new TextNode(value.getId.getBase64Url))
255+
.set[ObjectNode]("rawId", new TextNode(modId.getBase64Url))
256+
val reencoded = json.writeValueAsString(decoded)
257+
258+
an [ValueInstantiationException] should be thrownBy {
259+
json.readValue(reencoded, tpe)
260+
}
261+
}
262+
}
263+
264+
test(new TypeReference[PublicKeyCredential[AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs]](){})
265+
test(new TypeReference[PublicKeyCredential[AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs]](){})
266+
}
164267
}
165268

166269
}

0 commit comments

Comments
 (0)