diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorAttachment.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorAttachment.java index 96c666659..d5d338b42 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorAttachment.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/data/AuthenticatorAttachment.java @@ -26,7 +26,6 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; -import java.util.Optional; import java.util.stream.Stream; import lombok.AllArgsConstructor; import lombok.Getter; @@ -73,18 +72,8 @@ public enum AuthenticatorAttachment { @JsonValue @Getter @NonNull private final String value; - private static Optional fromString(@NonNull String value) { - return Stream.of(values()).filter(v -> v.value.equals(value)).findAny(); - } - @JsonCreator private static AuthenticatorAttachment fromJsonString(@NonNull String value) { - return fromString(value) - .orElseThrow( - () -> - new IllegalArgumentException( - String.format( - "Unknown %s value: %s", - AuthenticatorAttachment.class.getSimpleName(), value))); + return Stream.of(values()).filter(v -> v.value.equals(value)).findAny().orElse(null); } } diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/EnumsSpec.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/EnumsSpec.scala index 8e35e8558..dbe5ca609 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/EnumsSpec.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/EnumsSpec.scala @@ -61,11 +61,10 @@ class EnumsSpec describe("AuthenticatorAttachment") { describe("can be parsed from JSON") { - it("but throws IllegalArgumentException for unknown values.") { - val result = Try( + it("and ignores for unknown values.") { + val result = json.readValue("\"foo\"", classOf[AuthenticatorAttachment]) - ) - result.failed.get.getCause shouldBe an[IllegalArgumentException] + result should be(null) } } } diff --git a/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/JsonIoSpec.scala b/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/JsonIoSpec.scala index 29cfa491f..0fd026f9b 100644 --- a/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/JsonIoSpec.scala +++ b/webauthn-server-core/src/test/scala/com/yubico/webauthn/data/JsonIoSpec.scala @@ -41,12 +41,13 @@ import com.yubico.webauthn.extension.appid.Generators._ import org.junit.runner.RunWith import org.scalacheck.Arbitrary import org.scalacheck.Arbitrary.arbitrary -import org.scalacheck.Gen import org.scalatest.funspec.AnyFunSpec import org.scalatest.matchers.should.Matchers import org.scalatestplus.junit.JUnitRunner import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks +import scala.jdk.OptionConverters.RichOptional + @RunWith(classOf[JUnitRunner]) class JsonIoSpec extends AnyFunSpec @@ -351,15 +352,16 @@ class JsonIoSpec ) } - it("allows and ignores an authenticatorAttachment attribute.") { + it( + "allows an authenticatorAttachment attribute, but ignores unknown values." + ) { def test[P <: PublicKeyCredential[_, _]](tpe: TypeReference[P])(implicit a: Arbitrary[P] ): Unit = { forAll( a.arbitrary, - Gen.oneOf( - arbitrary[AuthenticatorAttachment].map(_.getValue), - arbitrary[String], + arbitrary[String].suchThat(s => + !AuthenticatorAttachment.values.map(_.getValue).contains(s) ), ) { (value: P, authenticatorAttachment: String) => val tree: ObjectNode = json.valueToTree(value) @@ -370,8 +372,37 @@ class JsonIoSpec val encoded = json.writeValueAsString(tree) println(authenticatorAttachment) val decoded = json.readValue(encoded, tpe) + decoded.getAuthenticatorAttachment.asScala should be(None) + } + + forAll( + a.arbitrary, + arbitrary[AuthenticatorAttachment], + ) { (value: P, authenticatorAttachment: AuthenticatorAttachment) => + val tree: ObjectNode = json.valueToTree(value) + tree.set( + "authenticatorAttachment", + new TextNode(authenticatorAttachment.getValue), + ) + val encoded = json.writeValueAsString(tree) + println(authenticatorAttachment) + val decoded = json.readValue(encoded, tpe) + + decoded.getAuthenticatorAttachment.asScala should equal( + Some(authenticatorAttachment) + ) + } + + forAll( + a.arbitrary + ) { (value: P) => + val tree: ObjectNode = json.valueToTree( + value.toBuilder.authenticatorAttachment(null).build() + ) + val encoded = json.writeValueAsString(tree) + val decoded = json.readValue(encoded, tpe) - decoded should equal(value) + decoded.getAuthenticatorAttachment.asScala should be(None) } }