diff --git a/webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsJackson2Deserializer.java b/webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsJackson2Deserializer.java index 85f3f4b2a3..0be604462b 100644 --- a/webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsJackson2Deserializer.java +++ b/webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsJackson2Deserializer.java @@ -62,11 +62,8 @@ class AuthenticationExtensionsClientOutputsJackson2Deserializer throws IOException, JacksonException { List> outputs = new ArrayList<>(); for (String key = parser.nextFieldName(); key != null; key = parser.nextFieldName()) { - JsonToken startObject = parser.nextValue(); - if (startObject != JsonToken.START_OBJECT) { - break; - } - if (CredentialPropertiesOutput.EXTENSION_ID.equals(key)) { + JsonToken next = parser.nextToken(); + if (next == JsonToken.START_OBJECT && CredentialPropertiesOutput.EXTENSION_ID.equals(key)) { CredentialPropertiesOutput output = parser.readValueAs(CredentialPropertiesOutput.class); outputs.add(output); } @@ -74,7 +71,9 @@ class AuthenticationExtensionsClientOutputsJackson2Deserializer if (logger.isDebugEnabled()) { logger.debug("Skipping unknown extension with id " + key); } - parser.nextValue(); + if (next.isStructStart()) { + parser.skipChildren(); + } } } diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/Jackson2Tests.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/Jackson2Tests.java index d93384cb13..5c203a1aac 100644 --- a/webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/Jackson2Tests.java +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/Jackson2Tests.java @@ -122,6 +122,47 @@ class Jackson2Tests { assertThat(outputs).usingRecursiveComparison().isEqualTo(credProps); } + @Test + void readAuthenticationExtensionsClientOutputsWhenAppId() throws Exception { + String json = """ + { + "appid": false, + "credProps": { + "rk": false + } + } + """; + CredentialPropertiesOutput credProps = new CredentialPropertiesOutput(false); + + AuthenticationExtensionsClientOutputs outputs = this.mapper.readValue(json, + AuthenticationExtensionsClientOutputs.class); + assertThat(outputs.getOutputs()).usingRecursiveFieldByFieldElementComparator().contains(credProps); + } + + @Test + void readAuthenticationExtensionsClientOutputsWhenUnknownExtension() throws Exception { + String json = """ + { + "unknownObject1": { + "key": "value" + }, + "unknownArray": [ + { "key": "value1" }, + { "key": "value2" } + ], + "credProps": { + "rk": false + }, + "unknownObject2": {} + } + """; + CredentialPropertiesOutput credProps = new CredentialPropertiesOutput(false); + + AuthenticationExtensionsClientOutputs outputs = this.mapper.readValue(json, + AuthenticationExtensionsClientOutputs.class); + assertThat(outputs.getOutputs()).usingRecursiveFieldByFieldElementComparator().contains(credProps); + } + @Test void readAuthenticationExtensionsClientOutputsWhenFieldAfter() throws Exception { String json = """