Browse Source

Add webauthn Jackson 3 support and deprecate Jackson 2 one

Since this module was already using the jackson sub-package for Jackson 2
support, both Jackson 2 and Jackson 3 support lives in the same subpackage
and the former package-private classes has been renamed with a Jackson2
qualifier.

See gh-17832
Signed-off-by: Sébastien Deleuze <sdeleuze@users.noreply.github.com>
Sébastien Deleuze 1 month ago
parent
commit
702a177e25
80 changed files with 2504 additions and 191 deletions
  1. 1 0
      webauthn/spring-security-webauthn.gradle
  2. 5 5
      webauthn/src/main/java/org/springframework/security/web/webauthn/authentication/PublicKeyCredentialRequestOptionsFilter.java
  3. 11 10
      webauthn/src/main/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationFilter.java
  4. 37 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AttestationConveyancePreferenceJackson2Mixin.java
  5. 50 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AttestationConveyancePreferenceJackson2Serializer.java
  6. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AttestationConveyancePreferenceMixin.java
  7. 6 7
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AttestationConveyancePreferenceSerializer.java
  8. 37 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputJackson2Mixin.java
  9. 53 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputJackson2Serializer.java
  10. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputMixin.java
  11. 7 8
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputSerializer.java
  12. 37 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsJackson2Mixin.java
  13. 59 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsJackson2Serializer.java
  14. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsMixin.java
  15. 7 8
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsSerializer.java
  16. 7 8
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsDeserializer.java
  17. 84 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsJackson2Deserializer.java
  18. 37 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsJackson2Mixin.java
  19. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsMixin.java
  20. 42 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAssertionResponseJackson2Mixin.java
  21. 2 2
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAssertionResponseMixin.java
  22. 58 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentJackson2Deserializer.java
  23. 39 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentJackson2Mixin.java
  24. 50 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentJackson2Serializer.java
  25. 2 2
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentMixin.java
  26. 6 7
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentSerializer.java
  27. 52 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttestationResponseJackson2Mixin.java
  28. 2 2
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttestationResponseMixin.java
  29. 58 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportJackson2Deserializer.java
  30. 39 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportJackson2Mixin.java
  31. 45 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportJackson2Serializer.java
  32. 2 2
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportMixin.java
  33. 7 8
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportSerializer.java
  34. 45 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/BytesJackson2Mixin.java
  35. 52 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/BytesJackson2Serializer.java
  36. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/BytesMixin.java
  37. 5 6
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/BytesSerializer.java
  38. 58 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierJackson2Deserializer.java
  39. 39 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierJackson2Mixin.java
  40. 50 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierJackson2Serializer.java
  41. 2 2
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierMixin.java
  42. 6 7
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierSerializer.java
  43. 31 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJackson2Mixin.java
  44. 68 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJackson2Serializer.java
  45. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputMixin.java
  46. 7 8
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputSerializer.java
  47. 40 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredentialPropertiesOutputJackson2Mixin.java
  48. 51 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/DurationJackson2Serializer.java
  49. 5 5
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/DurationSerializer.java
  50. 44 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialCreationOptionsJackson2Mixin.java
  51. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialCreationOptionsMixin.java
  52. 42 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialJackson2Mixin.java
  53. 2 2
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialMixin.java
  54. 44 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialRequestOptionsJackson2Mixin.java
  55. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialRequestOptionsMixin.java
  56. 5 8
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeDeserializer.java
  57. 55 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeJackson2Deserializer.java
  58. 39 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeJackson2Mixin.java
  59. 53 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeJackson2Serializer.java
  60. 2 2
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeMixin.java
  61. 6 7
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeSerializer.java
  62. 42 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/RelyingPartyPublicKeyJackson2Mixin.java
  63. 37 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/ResidentKeyRequirementJackson2Mixin.java
  64. 53 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/ResidentKeyRequirementJackson2Serializer.java
  65. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/ResidentKeyRequirementMixin.java
  66. 6 7
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/ResidentKeyRequirementSerializer.java
  67. 37 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/UserVerificationRequirementJackson2Mixin.java
  68. 53 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/UserVerificationRequirementJackson2Serializer.java
  69. 1 1
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/UserVerificationRequirementMixin.java
  70. 6 7
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/UserVerificationRequirementSerializer.java
  71. 29 23
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/WebauthnJackson2Module.java
  72. 97 0
      webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/WebauthnJacksonModule.java
  73. 6 6
      webauthn/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java
  74. 6 6
      webauthn/src/main/java/org/springframework/security/web/webauthn/registration/WebAuthnRegistrationFilter.java
  75. 2 2
      webauthn/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationFilterTests.java
  76. 153 0
      webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJackson2Tests.java
  77. 3 4
      webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJacksonTests.java
  78. 363 0
      webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/Jackson2Tests.java
  79. 4 5
      webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/JacksonTests.java
  80. 4 5
      webauthn/src/test/java/org/springframework/security/web/webauthn/registration/WebAuthnRegistrationRequestJacksonTests.java

+ 1 - 0
webauthn/spring-security-webauthn.gradle

@@ -15,6 +15,7 @@ dependencies {
 
 	optional 'org.springframework:spring-jdbc'
 	optional 'org.springframework:spring-tx'
+	optional 'tools.jackson.core:jackson-databind'
 
 	provided 'jakarta.servlet:jakarta.servlet-api'
 

+ 5 - 5
webauthn/src/main/java/org/springframework/security/web/webauthn/authentication/PublicKeyCredentialRequestOptionsFilter.java

@@ -22,13 +22,13 @@ import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import tools.jackson.databind.json.JsonMapper;
 
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
 import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
 import org.springframework.http.server.ServletServerHttpResponse;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -36,7 +36,7 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
 import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcher;
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
-import org.springframework.security.web.webauthn.jackson.WebauthnJackson2Module;
+import org.springframework.security.web.webauthn.jackson.WebauthnJacksonModule;
 import org.springframework.security.web.webauthn.management.ImmutablePublicKeyCredentialRequestOptionsRequest;
 import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations;
 import org.springframework.util.Assert;
@@ -63,8 +63,8 @@ public class PublicKeyCredentialRequestOptionsFilter extends OncePerRequestFilte
 
 	private PublicKeyCredentialRequestOptionsRepository requestOptionsRepository = new HttpSessionPublicKeyCredentialRequestOptionsRepository();
 
-	private HttpMessageConverter<Object> converter = new MappingJackson2HttpMessageConverter(
-			Jackson2ObjectMapperBuilder.json().modules(new WebauthnJackson2Module()).build());
+	private HttpMessageConverter<Object> converter = new JacksonJsonHttpMessageConverter(
+			JsonMapper.builder().addModule(new WebauthnJacksonModule()).build());
 
 	/**
 	 * Creates a new instance with the provided {@link WebAuthnRelyingPartyOperations}.

+ 11 - 10
webauthn/src/main/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationFilter.java

@@ -21,13 +21,14 @@ import java.io.IOException;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import tools.jackson.databind.json.JsonMapper;
 
 import org.springframework.core.ResolvableType;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.converter.GenericHttpMessageConverter;
-import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.converter.SmartHttpMessageConverter;
+import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
 import org.springframework.http.server.ServletServerHttpRequest;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
@@ -40,7 +41,7 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
 import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
 import org.springframework.security.web.webauthn.api.PublicKeyCredential;
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
-import org.springframework.security.web.webauthn.jackson.WebauthnJackson2Module;
+import org.springframework.security.web.webauthn.jackson.WebauthnJacksonModule;
 import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
 import org.springframework.util.Assert;
 
@@ -49,8 +50,7 @@ import static org.springframework.security.web.servlet.util.matcher.PathPatternR
 /**
  * Authenticates {@code PublicKeyCredential<AuthenticatorAssertionResponse>} that is
  * parsed from the body of the {@link HttpServletRequest} using the
- * {@link #setConverter(GenericHttpMessageConverter)}. An example request is provided
- * below:
+ * {@link #setConverter(SmartHttpMessageConverter)}. An example request is provided below:
  *
  * <pre>
  * {
@@ -72,8 +72,8 @@ import static org.springframework.security.web.servlet.util.matcher.PathPatternR
  */
 public class WebAuthnAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
 
-	private GenericHttpMessageConverter<Object> converter = new MappingJackson2HttpMessageConverter(
-			Jackson2ObjectMapperBuilder.json().modules(new WebauthnJackson2Module()).build());
+	private SmartHttpMessageConverter<Object> converter = new JacksonJsonHttpMessageConverter(
+			JsonMapper.builder().addModule(new WebauthnJacksonModule()).build());
 
 	private PublicKeyCredentialRequestOptionsRepository requestOptionsRepository = new HttpSessionPublicKeyCredentialRequestOptionsRepository();
 
@@ -94,7 +94,7 @@ public class WebAuthnAuthenticationFilter extends AbstractAuthenticationProcessi
 		PublicKeyCredential<AuthenticatorAssertionResponse> publicKeyCredential = null;
 		try {
 			publicKeyCredential = (PublicKeyCredential<AuthenticatorAssertionResponse>) this.converter
-				.read(resolvableType.getType(), getClass(), httpRequest);
+				.read(resolvableType, httpRequest, null);
 		}
 		catch (Exception ex) {
 			throw new BadCredentialsException("Unable to authenticate the PublicKeyCredential", ex);
@@ -114,10 +114,11 @@ public class WebAuthnAuthenticationFilter extends AbstractAuthenticationProcessi
 	/**
 	 * Sets the {@link GenericHttpMessageConverter} to use for writing
 	 * {@code PublicKeyCredential<AuthenticatorAssertionResponse>} to the response. The
-	 * default is @{code MappingJackson2HttpMessageConverter}
+	 * default is @{code Jackson2HttpMessageConverter}
 	 * @param converter the {@link GenericHttpMessageConverter} to use. Cannot be null.
 	 */
-	public void setConverter(GenericHttpMessageConverter<Object> converter) {
+	// TODO Accept HttpMessageConverter
+	public void setConverter(SmartHttpMessageConverter<Object> converter) {
 		Assert.notNull(converter, "converter cannot be null");
 		this.converter = converter;
 	}

+ 37 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AttestationConveyancePreferenceJackson2Mixin.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
+
+/**
+ * Jackson mixin for {@link AttestationConveyancePreference}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AttestationConveyancePreferenceMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = AttestationConveyancePreferenceJackson2Serializer.class)
+class AttestationConveyancePreferenceJackson2Mixin {
+
+}

+ 50 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AttestationConveyancePreferenceJackson2Serializer.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
+
+/**
+ * Jackson serializer for {@link AttestationConveyancePreference}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AttestationConveyancePreferenceSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class AttestationConveyancePreferenceJackson2Serializer extends StdSerializer<AttestationConveyancePreference> {
+
+	AttestationConveyancePreferenceJackson2Serializer() {
+		super(AttestationConveyancePreference.class);
+	}
+
+	@Override
+	public void serialize(AttestationConveyancePreference preference, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeString(preference.getValue());
+	}
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AttestationConveyancePreferenceMixin.java

@@ -16,7 +16,7 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
 

+ 6 - 7
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AttestationConveyancePreferenceSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
 
@@ -38,8 +37,8 @@ class AttestationConveyancePreferenceSerializer extends StdSerializer<Attestatio
 	}
 
 	@Override
-	public void serialize(AttestationConveyancePreference preference, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
+	public void serialize(AttestationConveyancePreference preference, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
 		jgen.writeString(preference.getValue());
 	}
 

+ 37 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputJackson2Mixin.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
+
+/**
+ * Jackson mixin for {@link AuthenticationExtensionsClientInputs}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticationExtensionsClientInputMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = AuthenticationExtensionsClientInputJackson2Serializer.class)
+class AuthenticationExtensionsClientInputJackson2Mixin {
+
+}

+ 53 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputJackson2Serializer.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInput;
+
+/**
+ * Provides Jackson serialization of {@link AuthenticationExtensionsClientInput}.
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticationExtensionsClientInputSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class AuthenticationExtensionsClientInputJackson2Serializer extends StdSerializer<AuthenticationExtensionsClientInput> {
+
+	/**
+	 * Creates a new instance.
+	 */
+	AuthenticationExtensionsClientInputJackson2Serializer() {
+		super(AuthenticationExtensionsClientInput.class);
+	}
+
+	@Override
+	public void serialize(AuthenticationExtensionsClientInput input, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeObjectField(input.getExtensionId(), input.getInput());
+	}
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputMixin.java

@@ -16,7 +16,7 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
 

+ 7 - 8
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInput;
 
@@ -41,9 +40,9 @@ class AuthenticationExtensionsClientInputSerializer extends StdSerializer<Authen
 	}
 
 	@Override
-	public void serialize(AuthenticationExtensionsClientInput input, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
-		jgen.writeObjectField(input.getExtensionId(), input.getInput());
+	public void serialize(AuthenticationExtensionsClientInput input, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
+		jgen.writePOJOProperty(input.getExtensionId(), input.getInput());
 	}
 
 }

+ 37 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsJackson2Mixin.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
+
+/**
+ * Jackson mixin for {@link AuthenticationExtensionsClientInputs}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticationExtensionsClientInputsMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = AuthenticationExtensionsClientInputsJackson2Serializer.class)
+class AuthenticationExtensionsClientInputsJackson2Mixin {
+
+}

+ 59 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsJackson2Serializer.java

@@ -0,0 +1,59 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInput;
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
+
+/**
+ * Provides Jackson serialization of {@link AuthenticationExtensionsClientInputs}.
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticationExtensionsClientInputsSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class AuthenticationExtensionsClientInputsJackson2Serializer
+		extends StdSerializer<AuthenticationExtensionsClientInputs> {
+
+	/**
+	 * Creates a new instance.
+	 */
+	AuthenticationExtensionsClientInputsJackson2Serializer() {
+		super(AuthenticationExtensionsClientInputs.class);
+	}
+
+	@Override
+	public void serialize(AuthenticationExtensionsClientInputs inputs, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeStartObject();
+		for (AuthenticationExtensionsClientInput input : inputs.getInputs()) {
+			jgen.writeObject(input);
+		}
+		jgen.writeEndObject();
+	}
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsMixin.java

@@ -16,7 +16,7 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
 

+ 7 - 8
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInput;
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
@@ -42,11 +41,11 @@ class AuthenticationExtensionsClientInputsSerializer extends StdSerializer<Authe
 	}
 
 	@Override
-	public void serialize(AuthenticationExtensionsClientInputs inputs, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
+	public void serialize(AuthenticationExtensionsClientInputs inputs, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
 		jgen.writeStartObject();
 		for (AuthenticationExtensionsClientInput input : inputs.getInputs()) {
-			jgen.writeObject(input);
+			jgen.writePOJO(input);
 		}
 		jgen.writeEndObject();
 	}

+ 7 - 8
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsDeserializer.java

@@ -16,17 +16,16 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
-import com.fasterxml.jackson.core.JacksonException;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonToken;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonParser;
+import tools.jackson.core.JsonToken;
+import tools.jackson.databind.DeserializationContext;
+import tools.jackson.databind.deser.std.StdDeserializer;
 
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutput;
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
@@ -53,9 +52,9 @@ class AuthenticationExtensionsClientOutputsDeserializer extends StdDeserializer<
 
 	@Override
 	public AuthenticationExtensionsClientOutputs deserialize(JsonParser parser, DeserializationContext ctxt)
-			throws IOException, JacksonException {
+			throws JacksonException {
 		List<AuthenticationExtensionsClientOutput<?>> outputs = new ArrayList<>();
-		for (String key = parser.nextFieldName(); key != null; key = parser.nextFieldName()) {
+		for (String key = parser.nextName(); key != null; key = parser.nextName()) {
 			JsonToken startObject = parser.nextValue();
 			if (startObject != JsonToken.START_OBJECT) {
 				break;

+ 84 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsJackson2Deserializer.java

@@ -0,0 +1,84 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutput;
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
+import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
+import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs;
+
+/**
+ * Provides Jackson deserialization of {@link AuthenticationExtensionsClientOutputs}.
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticationExtensionsClientOutputsDeserializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class AuthenticationExtensionsClientOutputsJackson2Deserializer
+		extends StdDeserializer<AuthenticationExtensionsClientOutputs> {
+
+	private static final Log logger = LogFactory
+		.getLog(AuthenticationExtensionsClientOutputsJackson2Deserializer.class);
+
+	/**
+	 * Creates a new instance.
+	 */
+	AuthenticationExtensionsClientOutputsJackson2Deserializer() {
+		super(AuthenticationExtensionsClientOutputs.class);
+	}
+
+	@Override
+	public AuthenticationExtensionsClientOutputs deserialize(JsonParser parser, DeserializationContext ctxt)
+			throws IOException, JacksonException {
+		List<AuthenticationExtensionsClientOutput<?>> 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)) {
+				CredentialPropertiesOutput output = parser.readValueAs(CredentialPropertiesOutput.class);
+				outputs.add(output);
+			}
+			else {
+				if (logger.isDebugEnabled()) {
+					logger.debug("Skipping unknown extension with id " + key);
+				}
+				parser.nextValue();
+			}
+		}
+
+		return new ImmutableAuthenticationExtensionsClientOutputs(outputs);
+	}
+
+}

+ 37 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsJackson2Mixin.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
+
+/**
+ * Jackson mixin for {@link AuthenticationExtensionsClientOutputs}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticationExtensionsClientOutputsMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonDeserialize(using = AuthenticationExtensionsClientOutputsJackson2Deserializer.class)
+class AuthenticationExtensionsClientOutputsJackson2Mixin {
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientOutputsMixin.java

@@ -16,7 +16,7 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.annotation.JsonDeserialize;
 
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
 

+ 42 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAssertionResponseJackson2Mixin.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
+
+/**
+ * Jackson mixin for {@link AuthenticatorAssertionResponse}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticatorAssertionResponseMixin}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@JsonDeserialize(builder = AuthenticatorAssertionResponse.AuthenticatorAssertionResponseBuilder.class)
+class AuthenticatorAssertionResponseJackson2Mixin {
+
+	@JsonPOJOBuilder(withPrefix = "")
+	abstract class AuthenticatorAssertionResponseBuilderMixin {
+
+	}
+
+}

+ 2 - 2
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAssertionResponseMixin.java

@@ -16,8 +16,8 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.annotation.JsonPOJOBuilder;
 
 import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
 

+ 58 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentJackson2Deserializer.java

@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.jspecify.annotations.Nullable;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
+
+/**
+ * Jackson deserializer for {@link AuthenticatorAttachment}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticatorAttachmentDeserializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class AuthenticatorAttachmentJackson2Deserializer extends StdDeserializer<AuthenticatorAttachment> {
+
+	AuthenticatorAttachmentJackson2Deserializer() {
+		super(AuthenticatorAttachment.class);
+	}
+
+	@Override
+	public @Nullable AuthenticatorAttachment deserialize(JsonParser parser, DeserializationContext ctxt)
+			throws IOException, JacksonException {
+		String type = parser.readValueAs(String.class);
+		for (AuthenticatorAttachment publicKeyCredentialType : AuthenticatorAttachment.values()) {
+			if (publicKeyCredentialType.getValue().equals(type)) {
+				return publicKeyCredentialType;
+			}
+		}
+		return null;
+	}
+
+}

+ 39 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentJackson2Mixin.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
+
+/**
+ * Jackson mixin for {@link AuthenticatorAttachment}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticatorAttachmentMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonDeserialize(using = AuthenticatorAttachmentJackson2Deserializer.class)
+@JsonSerialize(using = AuthenticatorAttachmentJackson2Serializer.class)
+class AuthenticatorAttachmentJackson2Mixin {
+
+}

+ 50 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentJackson2Serializer.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
+
+/**
+ * Jackson serializer for {@link AuthenticatorAttachment}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticatorAttachmentSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class AuthenticatorAttachmentJackson2Serializer extends StdSerializer<AuthenticatorAttachment> {
+
+	AuthenticatorAttachmentJackson2Serializer() {
+		super(AuthenticatorAttachment.class);
+	}
+
+	@Override
+	public void serialize(AuthenticatorAttachment attachment, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeString(attachment.getValue());
+	}
+
+}

+ 2 - 2
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentMixin.java

@@ -16,8 +16,8 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
 

+ 6 - 7
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttachmentSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
 
@@ -38,8 +37,8 @@ class AuthenticatorAttachmentSerializer extends StdSerializer<AuthenticatorAttac
 	}
 
 	@Override
-	public void serialize(AuthenticatorAttachment attachment, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
+	public void serialize(AuthenticatorAttachment attachment, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
 		jgen.writeString(attachment.getValue());
 	}
 

+ 52 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttestationResponseJackson2Mixin.java

@@ -0,0 +1,52 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
+import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
+
+/**
+ * Jackson mixin for {@link AuthenticatorAttestationResponse}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticatorAttestationResponseMixin}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@JsonDeserialize(builder = AuthenticatorAttestationResponse.AuthenticatorAttestationResponseBuilder.class)
+class AuthenticatorAttestationResponseJackson2Mixin {
+
+	@JsonPOJOBuilder(withPrefix = "")
+	@JsonIgnoreProperties(ignoreUnknown = true)
+	abstract class AuthenticatorAttestationResponseBuilderMixin {
+
+		@JsonSetter
+		abstract AuthenticatorAttestationResponse.AuthenticatorAttestationResponseBuilder transports(
+				List<AuthenticatorTransport> transports);
+
+	}
+
+}

+ 2 - 2
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorAttestationResponseMixin.java

@@ -20,8 +20,8 @@ import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.annotation.JsonSetter;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.annotation.JsonPOJOBuilder;
 
 import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
 import org.springframework.security.web.webauthn.api.AuthenticatorTransport;

+ 58 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportJackson2Deserializer.java

@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.jspecify.annotations.Nullable;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
+
+/**
+ * Jackson deserializer for {@link AuthenticatorTransport}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticatorTransportDeserializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class AuthenticatorTransportJackson2Deserializer extends StdDeserializer<AuthenticatorTransport> {
+
+	AuthenticatorTransportJackson2Deserializer() {
+		super(AuthenticatorTransport.class);
+	}
+
+	@Override
+	public @Nullable AuthenticatorTransport deserialize(JsonParser parser, DeserializationContext ctxt)
+			throws IOException, JacksonException {
+		String transportValue = parser.readValueAs(String.class);
+		for (AuthenticatorTransport transport : AuthenticatorTransport.values()) {
+			if (transport.getValue().equals(transportValue)) {
+				return transport;
+			}
+		}
+		return null;
+	}
+
+}

+ 39 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportJackson2Mixin.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
+
+/**
+ * Jackson mixin for {@link AuthenticatorTransport}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticatorTransportMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonDeserialize(using = AuthenticatorTransportJackson2Deserializer.class)
+@JsonSerialize(using = AuthenticatorTransportJackson2Serializer.class)
+class AuthenticatorTransportJackson2Mixin {
+
+}

+ 45 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportJackson2Serializer.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
+
+/**
+ * Jackson serializer for {@link AuthenticatorTransport}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.AuthenticatorTransportSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+class AuthenticatorTransportJackson2Serializer extends JsonSerializer<AuthenticatorTransport> {
+
+	@Override
+	public void serialize(AuthenticatorTransport transport, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeString(transport.getValue());
+	}
+
+}

+ 2 - 2
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportMixin.java

@@ -16,8 +16,8 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
 

+ 7 - 8
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorTransportSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ValueSerializer;
 
 import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
 
@@ -30,11 +29,11 @@ import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
  * @author Rob Winch
  * @since 6.4
  */
-class AuthenticatorTransportSerializer extends JsonSerializer<AuthenticatorTransport> {
+class AuthenticatorTransportSerializer extends ValueSerializer<AuthenticatorTransport> {
 
 	@Override
-	public void serialize(AuthenticatorTransport transport, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
+	public void serialize(AuthenticatorTransport transport, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
 		jgen.writeString(transport.getValue());
 	}
 

+ 45 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/BytesJackson2Mixin.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.Bytes;
+
+/**
+ * Jackson mixin for {@link Bytes}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.BytesMixin} based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = BytesJackson2Serializer.class)
+final class BytesJackson2Mixin {
+
+	@JsonCreator
+	static Bytes fromBase64(String value) {
+		return Bytes.fromBase64(value);
+	}
+
+	private BytesJackson2Mixin() {
+	}
+
+}

+ 52 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/BytesJackson2Serializer.java

@@ -0,0 +1,52 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.Bytes;
+
+/**
+ * Jackson serializer for {@link Bytes}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.BytesSerializer} based on
+ * Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class BytesJackson2Serializer extends StdSerializer<Bytes> {
+
+	/**
+	 * Creates a new instance.
+	 */
+	BytesJackson2Serializer() {
+		super(Bytes.class);
+	}
+
+	@Override
+	public void serialize(Bytes bytes, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+		jgen.writeString(bytes.toBase64UrlString());
+	}
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/BytesMixin.java

@@ -17,7 +17,7 @@
 package org.springframework.security.web.webauthn.jackson;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.Bytes;
 

+ 5 - 6
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/BytesSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.Bytes;
 
@@ -41,7 +40,7 @@ class BytesSerializer extends StdSerializer<Bytes> {
 	}
 
 	@Override
-	public void serialize(Bytes bytes, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+	public void serialize(Bytes bytes, JsonGenerator jgen, SerializationContext provider) throws JacksonException {
 		jgen.writeString(bytes.toBase64UrlString());
 	}
 

+ 58 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierJackson2Deserializer.java

@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import org.jspecify.annotations.Nullable;
+
+import org.springframework.security.web.webauthn.api.COSEAlgorithmIdentifier;
+
+/**
+ * Jackson serializer for {@link COSEAlgorithmIdentifier}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.COSEAlgorithmIdentifierDeserializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class COSEAlgorithmIdentifierJackson2Deserializer extends StdDeserializer<COSEAlgorithmIdentifier> {
+
+	COSEAlgorithmIdentifierJackson2Deserializer() {
+		super(COSEAlgorithmIdentifier.class);
+	}
+
+	@Override
+	public @Nullable COSEAlgorithmIdentifier deserialize(JsonParser parser, DeserializationContext ctxt)
+			throws IOException, JacksonException {
+		Long transportValue = parser.readValueAs(Long.class);
+		for (COSEAlgorithmIdentifier identifier : COSEAlgorithmIdentifier.values()) {
+			if (identifier.getValue() == transportValue.longValue()) {
+				return identifier;
+			}
+		}
+		return null;
+	}
+
+}

+ 39 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierJackson2Mixin.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.COSEAlgorithmIdentifier;
+
+/**
+ * Jackson mixin for {@link COSEAlgorithmIdentifier}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.COSEAlgorithmIdentifierMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = COSEAlgorithmIdentifierJackson2Serializer.class)
+@JsonDeserialize(using = COSEAlgorithmIdentifierJackson2Deserializer.class)
+abstract class COSEAlgorithmIdentifierJackson2Mixin {
+
+}

+ 50 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierJackson2Serializer.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.COSEAlgorithmIdentifier;
+
+/**
+ * Jackson serializer for {@link COSEAlgorithmIdentifier}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.COSEAlgorithmIdentifierSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class COSEAlgorithmIdentifierJackson2Serializer extends StdSerializer<COSEAlgorithmIdentifier> {
+
+	COSEAlgorithmIdentifierJackson2Serializer() {
+		super(COSEAlgorithmIdentifier.class);
+	}
+
+	@Override
+	public void serialize(COSEAlgorithmIdentifier identifier, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeNumber(identifier.getValue());
+	}
+
+}

+ 2 - 2
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierMixin.java

@@ -16,8 +16,8 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.COSEAlgorithmIdentifier;
 

+ 6 - 7
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/COSEAlgorithmIdentifierSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.COSEAlgorithmIdentifier;
 
@@ -38,8 +37,8 @@ class COSEAlgorithmIdentifierSerializer extends StdSerializer<COSEAlgorithmIdent
 	}
 
 	@Override
-	public void serialize(COSEAlgorithmIdentifier identifier, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
+	public void serialize(COSEAlgorithmIdentifier identifier, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
 		jgen.writeNumber(identifier.getValue());
 	}
 

+ 31 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJackson2Mixin.java

@@ -0,0 +1,31 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+/**
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.CredProtectAuthenticationExtensionsClientInputMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = CredProtectAuthenticationExtensionsClientInputJackson2Serializer.class)
+class CredProtectAuthenticationExtensionsClientInputJackson2Mixin {
+
+}

+ 68 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJackson2Serializer.java

@@ -0,0 +1,68 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
+
+/**
+ * Serializes <a href=
+ * "https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-credProtect-extension">credProtect
+ * extension</a>.
+ *
+ * @author Rob Winch
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.CredProtectAuthenticationExtensionsClientInputSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class CredProtectAuthenticationExtensionsClientInputJackson2Serializer
+		extends StdSerializer<CredProtectAuthenticationExtensionsClientInput> {
+
+	protected CredProtectAuthenticationExtensionsClientInputJackson2Serializer() {
+		super(CredProtectAuthenticationExtensionsClientInput.class);
+	}
+
+	@Override
+	public void serialize(CredProtectAuthenticationExtensionsClientInput input, JsonGenerator jgen,
+			SerializerProvider provider) throws IOException {
+		CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = input.getInput();
+		String policy = toString(credProtect.getCredProtectionPolicy());
+		jgen.writeObjectField("credentialProtectionPolicy", policy);
+		jgen.writeObjectField("enforceCredentialProtectionPolicy", credProtect.isEnforceCredentialProtectionPolicy());
+	}
+
+	private static String toString(CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy policy) {
+		switch (policy) {
+			case USER_VERIFICATION_OPTIONAL:
+				return "userVerificationOptional";
+			case USER_VERIFICATION_OPTIONAL_WITH_CREDENTIAL_ID_LIST:
+				return "userVerificationOptionalWithCredentialIdList";
+			case USER_VERIFICATION_REQUIRED:
+				return "userVerificationRequired";
+			default:
+				throw new IllegalArgumentException("Unsupported ProtectionPolicy " + policy);
+		}
+	}
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputMixin.java

@@ -16,7 +16,7 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 @JsonSerialize(using = CredProtectAuthenticationExtensionsClientInputSerializer.class)
 class CredProtectAuthenticationExtensionsClientInputMixin {

+ 7 - 8
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
 
@@ -41,11 +40,11 @@ class CredProtectAuthenticationExtensionsClientInputSerializer
 
 	@Override
 	public void serialize(CredProtectAuthenticationExtensionsClientInput input, JsonGenerator jgen,
-			SerializerProvider provider) throws IOException {
+			SerializationContext ctxt) throws JacksonException {
 		CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = input.getInput();
 		String policy = toString(credProtect.getCredProtectionPolicy());
-		jgen.writeObjectField("credentialProtectionPolicy", policy);
-		jgen.writeObjectField("enforceCredentialProtectionPolicy", credProtect.isEnforceCredentialProtectionPolicy());
+		jgen.writePOJOProperty("credentialProtectionPolicy", policy);
+		jgen.writePOJOProperty("enforceCredentialProtectionPolicy", credProtect.isEnforceCredentialProtectionPolicy());
 	}
 
 	private static String toString(CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy policy) {

+ 40 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/CredentialPropertiesOutputJackson2Mixin.java

@@ -0,0 +1,40 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
+
+/**
+ * Jackson mixin for {@link CredentialPropertiesOutput}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.CredentialPropertiesOutputMixin}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@JsonIgnoreProperties(ignoreUnknown = true)
+abstract class CredentialPropertiesOutputJackson2Mixin {
+
+	CredentialPropertiesOutputJackson2Mixin(@JsonProperty("rk") boolean rk) {
+	}
+
+}

+ 51 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/DurationJackson2Serializer.java

@@ -0,0 +1,51 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+import java.time.Duration;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+/**
+ * Jackson serializer for {@link Duration}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.DurationSerializer} based on
+ * Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class DurationJackson2Serializer extends StdSerializer<Duration> {
+
+	/**
+	 * Creates an instance.
+	 */
+	DurationJackson2Serializer() {
+		super(Duration.class);
+	}
+
+	@Override
+	public void serialize(Duration duration, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+		jgen.writeNumber(duration.toMillis());
+	}
+
+}

+ 5 - 5
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/DurationSerializer.java

@@ -16,12 +16,12 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
 import java.time.Duration;
 
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 /**
  * Jackson serializer for {@link Duration}
@@ -40,7 +40,7 @@ class DurationSerializer extends StdSerializer<Duration> {
 	}
 
 	@Override
-	public void serialize(Duration duration, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+	public void serialize(Duration duration, JsonGenerator jgen, SerializationContext ctxt) throws JacksonException {
 		jgen.writeNumber(duration.toMillis());
 	}
 

+ 44 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialCreationOptionsJackson2Mixin.java

@@ -0,0 +1,44 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.time.Duration;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.jspecify.annotations.Nullable;
+
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
+
+/**
+ * Jackson mixin for {@link PublicKeyCredentialCreationOptions}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.PublicKeyCredentialCreationOptionsMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+abstract class PublicKeyCredentialCreationOptionsJackson2Mixin {
+
+	@JsonSerialize(using = DurationJackson2Serializer.class)
+	private @Nullable Duration timeout;
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialCreationOptionsMixin.java

@@ -19,8 +19,8 @@ package org.springframework.security.web.webauthn.jackson;
 import java.time.Duration;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import org.jspecify.annotations.Nullable;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
 

+ 42 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialJackson2Mixin.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+
+import org.springframework.security.web.webauthn.api.PublicKeyCredential;
+
+/**
+ * Jackson mixin for {@link PublicKeyCredential}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.PublicKeyCredentialMixin}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@JsonDeserialize(builder = PublicKeyCredential.PublicKeyCredentialBuilder.class)
+class PublicKeyCredentialJackson2Mixin {
+
+	@JsonPOJOBuilder(withPrefix = "")
+	static class PublicKeyCredentialBuilderMixin {
+
+	}
+
+}

+ 2 - 2
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialMixin.java

@@ -16,8 +16,8 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.annotation.JsonPOJOBuilder;
 
 import org.springframework.security.web.webauthn.api.PublicKeyCredential;
 

+ 44 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialRequestOptionsJackson2Mixin.java

@@ -0,0 +1,44 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.time.Duration;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.jspecify.annotations.Nullable;
+
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
+
+/**
+ * Jackson mixin for {@link PublicKeyCredentialRequestOptions}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.PublicKeyCredentialRequestOptionsMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonInclude(content = JsonInclude.Include.NON_NULL)
+class PublicKeyCredentialRequestOptionsJackson2Mixin {
+
+	@JsonSerialize(using = DurationJackson2Serializer.class)
+	private final @Nullable Duration timeout = null;
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialRequestOptionsMixin.java

@@ -19,8 +19,8 @@ package org.springframework.security.web.webauthn.jackson;
 import java.time.Duration;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import org.jspecify.annotations.Nullable;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
 

+ 5 - 8
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeDeserializer.java

@@ -16,12 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JacksonException;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonParser;
+import tools.jackson.databind.DeserializationContext;
+import tools.jackson.databind.deser.std.StdDeserializer;
 
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
 
@@ -42,8 +40,7 @@ class PublicKeyCredentialTypeDeserializer extends StdDeserializer<PublicKeyCrede
 	}
 
 	@Override
-	public PublicKeyCredentialType deserialize(JsonParser parser, DeserializationContext ctxt)
-			throws IOException, JacksonException {
+	public PublicKeyCredentialType deserialize(JsonParser parser, DeserializationContext ctxt) throws JacksonException {
 		String type = parser.readValueAs(String.class);
 		return PublicKeyCredentialType.valueOf(type);
 	}

+ 55 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeJackson2Deserializer.java

@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
+
+/**
+ * Jackson deserializer for {@link PublicKeyCredentialType}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.PublicKeyCredentialTypeDeserializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class PublicKeyCredentialTypeJackson2Deserializer extends StdDeserializer<PublicKeyCredentialType> {
+
+	/**
+	 * Creates a new instance.
+	 */
+	PublicKeyCredentialTypeJackson2Deserializer() {
+		super(PublicKeyCredentialType.class);
+	}
+
+	@Override
+	public PublicKeyCredentialType deserialize(JsonParser parser, DeserializationContext ctxt)
+			throws IOException, JacksonException {
+		String type = parser.readValueAs(String.class);
+		return PublicKeyCredentialType.valueOf(type);
+	}
+
+}

+ 39 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeJackson2Mixin.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
+
+/**
+ * Jackson mixin for {@link PublicKeyCredentialType}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.PublicKeyCredentialTypeMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = PublicKeyCredentialTypeJackson2Serializer.class)
+@JsonDeserialize(using = PublicKeyCredentialTypeJackson2Deserializer.class)
+abstract class PublicKeyCredentialTypeJackson2Mixin {
+
+}

+ 53 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeJackson2Serializer.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
+
+/**
+ * Jackson serializer for {@link PublicKeyCredentialType}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.PublicKeyCredentialTypeSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class PublicKeyCredentialTypeJackson2Serializer extends StdSerializer<PublicKeyCredentialType> {
+
+	/**
+	 * Creates a new instance.
+	 */
+	PublicKeyCredentialTypeJackson2Serializer() {
+		super(PublicKeyCredentialType.class);
+	}
+
+	@Override
+	public void serialize(PublicKeyCredentialType type, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeString(type.getValue());
+	}
+
+}

+ 2 - 2
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeMixin.java

@@ -16,8 +16,8 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonDeserialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
 

+ 6 - 7
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialTypeSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
 
@@ -41,8 +40,8 @@ class PublicKeyCredentialTypeSerializer extends StdSerializer<PublicKeyCredentia
 	}
 
 	@Override
-	public void serialize(PublicKeyCredentialType type, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
+	public void serialize(PublicKeyCredentialType type, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
 		jgen.writeString(type.getValue());
 	}
 

+ 42 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/RelyingPartyPublicKeyJackson2Mixin.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
+import org.springframework.security.web.webauthn.api.PublicKeyCredential;
+import org.springframework.security.web.webauthn.management.RelyingPartyPublicKey;
+
+/**
+ * Jackson mixin for {@link RelyingPartyPublicKey}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.RelyingPartyPublicKeyMixin}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+abstract class RelyingPartyPublicKeyJackson2Mixin {
+
+	RelyingPartyPublicKeyJackson2Mixin(
+			@JsonProperty("credential") PublicKeyCredential<AuthenticatorAttestationResponse> credential,
+			@JsonProperty("label") String label) {
+	}
+
+}

+ 37 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/ResidentKeyRequirementJackson2Mixin.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.ResidentKeyRequirement;
+
+/**
+ * Jackson mixin for {@link ResidentKeyRequirement}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.ResidentKeyRequirementMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = ResidentKeyRequirementJackson2Serializer.class)
+abstract class ResidentKeyRequirementJackson2Mixin {
+
+}

+ 53 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/ResidentKeyRequirementJackson2Serializer.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.ResidentKeyRequirement;
+
+/**
+ * Jackson serializer for {@link ResidentKeyRequirement}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.ResidentKeyRequirementSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class ResidentKeyRequirementJackson2Serializer extends StdSerializer<ResidentKeyRequirement> {
+
+	/**
+	 * Creates a new instance.
+	 */
+	ResidentKeyRequirementJackson2Serializer() {
+		super(ResidentKeyRequirement.class);
+	}
+
+	@Override
+	public void serialize(ResidentKeyRequirement requirement, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeString(requirement.getValue());
+	}
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/ResidentKeyRequirementMixin.java

@@ -16,7 +16,7 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.ResidentKeyRequirement;
 

+ 6 - 7
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/ResidentKeyRequirementSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.ResidentKeyRequirement;
 
@@ -41,8 +40,8 @@ class ResidentKeyRequirementSerializer extends StdSerializer<ResidentKeyRequirem
 	}
 
 	@Override
-	public void serialize(ResidentKeyRequirement requirement, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
+	public void serialize(ResidentKeyRequirement requirement, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
 		jgen.writeString(requirement.getValue());
 	}
 

+ 37 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/UserVerificationRequirementJackson2Mixin.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
+
+/**
+ * Jackson mixin for {@link UserVerificationRequirement}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.UserVerificationRequirementMixin}
+ * based on Jackson 3
+ */
+@SuppressWarnings("removal")
+@Deprecated(forRemoval = true)
+@JsonSerialize(using = UserVerificationRequirementJackson2Serializer.class)
+abstract class UserVerificationRequirementJackson2Mixin {
+
+}

+ 53 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/UserVerificationRequirementJackson2Serializer.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
+
+/**
+ * Jackson serializer for {@link UserVerificationRequirement}
+ *
+ * @author Rob Winch
+ * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.UserVerificationRequirementSerializer}
+ * based on Jackson 3
+ */
+@Deprecated(forRemoval = true)
+@SuppressWarnings("serial")
+class UserVerificationRequirementJackson2Serializer extends StdSerializer<UserVerificationRequirement> {
+
+	/**
+	 * Creates a new instance.
+	 */
+	UserVerificationRequirementJackson2Serializer() {
+		super(UserVerificationRequirement.class);
+	}
+
+	@Override
+	public void serialize(UserVerificationRequirement requirement, JsonGenerator jgen, SerializerProvider provider)
+			throws IOException {
+		jgen.writeString(requirement.getValue());
+	}
+
+}

+ 1 - 1
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/UserVerificationRequirementMixin.java

@@ -16,7 +16,7 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import tools.jackson.databind.annotation.JsonSerialize;
 
 import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
 

+ 6 - 7
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/UserVerificationRequirementSerializer.java

@@ -16,11 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ser.std.StdSerializer;
 
 import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
 
@@ -41,8 +40,8 @@ class UserVerificationRequirementSerializer extends StdSerializer<UserVerificati
 	}
 
 	@Override
-	public void serialize(UserVerificationRequirement requirement, JsonGenerator jgen, SerializerProvider provider)
-			throws IOException {
+	public void serialize(UserVerificationRequirement requirement, JsonGenerator jgen, SerializationContext ctxt)
+			throws JacksonException {
 		jgen.writeString(requirement.getValue());
 	}
 

+ 29 - 23
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/WebauthnJackson2Module.java

@@ -46,8 +46,12 @@ import org.springframework.security.web.webauthn.management.RelyingPartyPublicKe
  *
  * @author Rob Winch
  * @since 6.4
+ * @deprecated as of 7.0 in favor of
+ * {@link org.springframework.security.web.webauthn.jackson.WebauthnJacksonModule} based
+ * on Jackson 3
  */
-@SuppressWarnings("serial")
+@Deprecated(forRemoval = true)
+@SuppressWarnings({ "serial", "removal" })
 public class WebauthnJackson2Module extends SimpleModule {
 
 	/**
@@ -59,39 +63,41 @@ public class WebauthnJackson2Module extends SimpleModule {
 
 	@Override
 	public void setupModule(SetupContext context) {
-		context.setMixInAnnotations(Bytes.class, BytesMixin.class);
-		context.setMixInAnnotations(AttestationConveyancePreference.class, AttestationConveyancePreferenceMixin.class);
+		context.setMixInAnnotations(Bytes.class, BytesJackson2Mixin.class);
+		context.setMixInAnnotations(AttestationConveyancePreference.class,
+				AttestationConveyancePreferenceJackson2Mixin.class);
 		context.setMixInAnnotations(AuthenticationExtensionsClientInput.class,
-				AuthenticationExtensionsClientInputMixin.class);
+				AuthenticationExtensionsClientInputJackson2Mixin.class);
 		context.setMixInAnnotations(AuthenticationExtensionsClientInputs.class,
-				AuthenticationExtensionsClientInputsMixin.class);
+				AuthenticationExtensionsClientInputsJackson2Mixin.class);
 		context.setMixInAnnotations(AuthenticationExtensionsClientOutputs.class,
-				AuthenticationExtensionsClientOutputsMixin.class);
+				AuthenticationExtensionsClientOutputsJackson2Mixin.class);
 		context.setMixInAnnotations(AuthenticatorAssertionResponse.AuthenticatorAssertionResponseBuilder.class,
-				AuthenticatorAssertionResponseMixin.AuthenticatorAssertionResponseBuilderMixin.class);
-		context.setMixInAnnotations(AuthenticatorAssertionResponse.class, AuthenticatorAssertionResponseMixin.class);
-		context.setMixInAnnotations(AuthenticatorAttachment.class, AuthenticatorAttachmentMixin.class);
+				AuthenticatorAssertionResponseJackson2Mixin.AuthenticatorAssertionResponseBuilderMixin.class);
+		context.setMixInAnnotations(AuthenticatorAssertionResponse.class,
+				AuthenticatorAssertionResponseJackson2Mixin.class);
+		context.setMixInAnnotations(AuthenticatorAttachment.class, AuthenticatorAttachmentJackson2Mixin.class);
 		context.setMixInAnnotations(AuthenticatorAttestationResponse.class,
-				AuthenticatorAttestationResponseMixin.class);
+				AuthenticatorAttestationResponseJackson2Mixin.class);
 		context.setMixInAnnotations(AuthenticatorAttestationResponse.AuthenticatorAttestationResponseBuilder.class,
-				AuthenticatorAttestationResponseMixin.AuthenticatorAttestationResponseBuilderMixin.class);
+				AuthenticatorAttestationResponseJackson2Mixin.AuthenticatorAttestationResponseBuilderMixin.class);
 		context.setMixInAnnotations(AuthenticatorSelectionCriteria.class, AuthenticatorSelectionCriteriaMixin.class);
-		context.setMixInAnnotations(AuthenticatorTransport.class, AuthenticatorTransportMixin.class);
-		context.setMixInAnnotations(COSEAlgorithmIdentifier.class, COSEAlgorithmIdentifierMixin.class);
-		context.setMixInAnnotations(CredentialPropertiesOutput.class, CredentialPropertiesOutputMixin.class);
+		context.setMixInAnnotations(AuthenticatorTransport.class, AuthenticatorTransportJackson2Mixin.class);
+		context.setMixInAnnotations(COSEAlgorithmIdentifier.class, COSEAlgorithmIdentifierJackson2Mixin.class);
+		context.setMixInAnnotations(CredentialPropertiesOutput.class, CredentialPropertiesOutputJackson2Mixin.class);
 		context.setMixInAnnotations(CredProtectAuthenticationExtensionsClientInput.class,
-				CredProtectAuthenticationExtensionsClientInputMixin.class);
+				CredProtectAuthenticationExtensionsClientInputJackson2Mixin.class);
 		context.setMixInAnnotations(PublicKeyCredential.PublicKeyCredentialBuilder.class,
-				PublicKeyCredentialMixin.PublicKeyCredentialBuilderMixin.class);
-		context.setMixInAnnotations(PublicKeyCredential.class, PublicKeyCredentialMixin.class);
+				PublicKeyCredentialJackson2Mixin.PublicKeyCredentialBuilderMixin.class);
+		context.setMixInAnnotations(PublicKeyCredential.class, PublicKeyCredentialJackson2Mixin.class);
 		context.setMixInAnnotations(PublicKeyCredentialCreationOptions.class,
-				PublicKeyCredentialCreationOptionsMixin.class);
+				PublicKeyCredentialCreationOptionsJackson2Mixin.class);
 		context.setMixInAnnotations(PublicKeyCredentialRequestOptions.class,
-				PublicKeyCredentialRequestOptionsMixin.class);
-		context.setMixInAnnotations(PublicKeyCredentialType.class, PublicKeyCredentialTypeMixin.class);
-		context.setMixInAnnotations(RelyingPartyPublicKey.class, RelyingPartyPublicKeyMixin.class);
-		context.setMixInAnnotations(ResidentKeyRequirement.class, ResidentKeyRequirementMixin.class);
-		context.setMixInAnnotations(UserVerificationRequirement.class, UserVerificationRequirementMixin.class);
+				PublicKeyCredentialRequestOptionsJackson2Mixin.class);
+		context.setMixInAnnotations(PublicKeyCredentialType.class, PublicKeyCredentialTypeJackson2Mixin.class);
+		context.setMixInAnnotations(RelyingPartyPublicKey.class, RelyingPartyPublicKeyJackson2Mixin.class);
+		context.setMixInAnnotations(ResidentKeyRequirement.class, ResidentKeyRequirementJackson2Mixin.class);
+		context.setMixInAnnotations(UserVerificationRequirement.class, UserVerificationRequirementJackson2Mixin.class);
 	}
 
 }

+ 97 - 0
webauthn/src/main/java/org/springframework/security/web/webauthn/jackson/WebauthnJacksonModule.java

@@ -0,0 +1,97 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import tools.jackson.core.Version;
+import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
+
+import org.springframework.security.jackson.SecurityJacksonModule;
+import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInput;
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
+import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
+import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
+import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
+import org.springframework.security.web.webauthn.api.AuthenticatorSelectionCriteria;
+import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
+import org.springframework.security.web.webauthn.api.Bytes;
+import org.springframework.security.web.webauthn.api.COSEAlgorithmIdentifier;
+import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
+import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
+import org.springframework.security.web.webauthn.api.PublicKeyCredential;
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
+import org.springframework.security.web.webauthn.api.ResidentKeyRequirement;
+import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
+import org.springframework.security.web.webauthn.management.RelyingPartyPublicKey;
+
+/**
+ * Adds Jackson support for Spring Security WebAuthn. It is automatically registered when
+ * using Jackson's SPI support.
+ *
+ * @author Sebastien Deleuze
+ * @author Rob Winch
+ * @since 7.0
+ */
+@SuppressWarnings("serial")
+public class WebauthnJacksonModule extends SecurityJacksonModule {
+
+	/**
+	 * Creates a new instance.
+	 */
+	public WebauthnJacksonModule() {
+		super(WebauthnJacksonModule.class.getName(), new Version(1, 0, 0, null, null, null));
+	}
+
+	@Override
+	public void configurePolymorphicTypeValidator(BasicPolymorphicTypeValidator.Builder builder) {
+	}
+
+	@Override
+	public void setupModule(SetupContext context) {
+		context.setMixIn(Bytes.class, BytesMixin.class);
+		context.setMixIn(AttestationConveyancePreference.class, AttestationConveyancePreferenceMixin.class);
+		context.setMixIn(AuthenticationExtensionsClientInput.class, AuthenticationExtensionsClientInputMixin.class);
+		context.setMixIn(AuthenticationExtensionsClientInputs.class, AuthenticationExtensionsClientInputsMixin.class);
+		context.setMixIn(AuthenticationExtensionsClientOutputs.class, AuthenticationExtensionsClientOutputsMixin.class);
+		context.setMixIn(AuthenticatorAssertionResponse.AuthenticatorAssertionResponseBuilder.class,
+				AuthenticatorAssertionResponseMixin.AuthenticatorAssertionResponseBuilderMixin.class);
+		context.setMixIn(AuthenticatorAssertionResponse.class, AuthenticatorAssertionResponseMixin.class);
+		context.setMixIn(AuthenticatorAttachment.class, AuthenticatorAttachmentMixin.class);
+		context.setMixIn(AuthenticatorAttestationResponse.class, AuthenticatorAttestationResponseMixin.class);
+		context.setMixIn(AuthenticatorAttestationResponse.AuthenticatorAttestationResponseBuilder.class,
+				AuthenticatorAttestationResponseMixin.AuthenticatorAttestationResponseBuilderMixin.class);
+		context.setMixIn(AuthenticatorSelectionCriteria.class, AuthenticatorSelectionCriteriaMixin.class);
+		context.setMixIn(AuthenticatorTransport.class, AuthenticatorTransportMixin.class);
+		context.setMixIn(COSEAlgorithmIdentifier.class, COSEAlgorithmIdentifierMixin.class);
+		context.setMixIn(CredentialPropertiesOutput.class, CredentialPropertiesOutputMixin.class);
+		context.setMixIn(CredProtectAuthenticationExtensionsClientInput.class,
+				CredProtectAuthenticationExtensionsClientInputMixin.class);
+		context.setMixIn(PublicKeyCredential.PublicKeyCredentialBuilder.class,
+				PublicKeyCredentialMixin.PublicKeyCredentialBuilderMixin.class);
+		context.setMixIn(PublicKeyCredential.class, PublicKeyCredentialMixin.class);
+		context.setMixIn(PublicKeyCredentialCreationOptions.class, PublicKeyCredentialCreationOptionsMixin.class);
+		context.setMixIn(PublicKeyCredentialRequestOptions.class, PublicKeyCredentialRequestOptionsMixin.class);
+		context.setMixIn(PublicKeyCredentialType.class, PublicKeyCredentialTypeMixin.class);
+		context.setMixIn(RelyingPartyPublicKey.class, RelyingPartyPublicKeyMixin.class);
+		context.setMixIn(ResidentKeyRequirement.class, ResidentKeyRequirementMixin.class);
+		context.setMixIn(UserVerificationRequirement.class, UserVerificationRequirementMixin.class);
+	}
+
+}

+ 6 - 6
webauthn/src/main/java/org/springframework/security/web/webauthn/registration/PublicKeyCredentialCreationOptionsFilter.java

@@ -23,13 +23,13 @@ import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import tools.jackson.databind.json.JsonMapper;
 
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.MediaType;
 import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
 import org.springframework.http.server.ServletServerHttpResponse;
 import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
 import org.springframework.security.authorization.AuthorizationManager;
@@ -41,7 +41,7 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
 import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
 import org.springframework.security.web.util.matcher.RequestMatcher;
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
-import org.springframework.security.web.webauthn.jackson.WebauthnJackson2Module;
+import org.springframework.security.web.webauthn.jackson.WebauthnJacksonModule;
 import org.springframework.security.web.webauthn.management.ImmutablePublicKeyCredentialCreationOptionsRequest;
 import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations;
 import org.springframework.util.Assert;
@@ -69,8 +69,8 @@ public class PublicKeyCredentialCreationOptionsFilter extends OncePerRequestFilt
 
 	private final WebAuthnRelyingPartyOperations rpOperations;
 
-	private HttpMessageConverter<Object> converter = new MappingJackson2HttpMessageConverter(
-			Jackson2ObjectMapperBuilder.json().modules(new WebauthnJackson2Module()).build());
+	private HttpMessageConverter<Object> converter = new JacksonJsonHttpMessageConverter(
+			JsonMapper.builder().addModule(new WebauthnJacksonModule()).build());
 
 	/**
 	 * Creates a new instance.
@@ -131,7 +131,7 @@ public class PublicKeyCredentialCreationOptionsFilter extends OncePerRequestFilt
 	/**
 	 * Set the {@link HttpMessageConverter} to read the
 	 * {@link WebAuthnRegistrationFilter.WebAuthnRegistrationRequest} and write the
-	 * response. The default is {@link MappingJackson2HttpMessageConverter}.
+	 * response. The default is {@link JacksonJsonHttpMessageConverter}.
 	 * @param converter the {@link HttpMessageConverter} to use. Cannot be null.
 	 */
 	public void setConverter(HttpMessageConverter<Object> converter) {

+ 6 - 6
webauthn/src/main/java/org/springframework/security/web/webauthn/registration/WebAuthnRegistrationFilter.java

@@ -18,7 +18,6 @@ package org.springframework.security.web.webauthn.registration;
 
 import java.io.IOException;
 
-import com.fasterxml.jackson.databind.json.JsonMapper;
 import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
@@ -26,13 +25,14 @@ import jakarta.servlet.http.HttpServletResponse;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.jspecify.annotations.Nullable;
+import tools.jackson.databind.json.JsonMapper;
 
 import org.springframework.http.HttpInputMessage;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
 import org.springframework.http.server.ServletServerHttpRequest;
 import org.springframework.http.server.ServletServerHttpResponse;
 import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
@@ -40,7 +40,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
 import org.springframework.security.web.webauthn.api.Bytes;
 import org.springframework.security.web.webauthn.api.CredentialRecord;
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
-import org.springframework.security.web.webauthn.jackson.WebauthnJackson2Module;
+import org.springframework.security.web.webauthn.jackson.WebauthnJacksonModule;
 import org.springframework.security.web.webauthn.management.ImmutableRelyingPartyRegistrationRequest;
 import org.springframework.security.web.webauthn.management.RelyingPartyPublicKey;
 import org.springframework.security.web.webauthn.management.UserCredentialRepository;
@@ -88,8 +88,8 @@ public class WebAuthnRegistrationFilter extends OncePerRequestFilter {
 
 	private final UserCredentialRepository userCredentials;
 
-	private HttpMessageConverter<Object> converter = new MappingJackson2HttpMessageConverter(
-			JsonMapper.builder().addModule(new WebauthnJackson2Module()).build());
+	private HttpMessageConverter<Object> converter = new JacksonJsonHttpMessageConverter(
+			JsonMapper.builder().addModule(new WebauthnJacksonModule()).build());
 
 	private PublicKeyCredentialCreationOptionsRepository creationOptionsRepository = new HttpSessionPublicKeyCredentialCreationOptionsRepository();
 
@@ -152,7 +152,7 @@ public class WebAuthnRegistrationFilter extends OncePerRequestFilter {
 	/**
 	 * Set the {@link HttpMessageConverter} to read the
 	 * {@link WebAuthnRegistrationRequest} and write the response. The default is
-	 * {@link MappingJackson2HttpMessageConverter}.
+	 * {@link JacksonJsonHttpMessageConverter}.
 	 * @param converter the {@link HttpMessageConverter} to use. Cannot be null.
 	 */
 	public void setConverter(HttpMessageConverter<Object> converter) {

+ 2 - 2
webauthn/src/test/java/org/springframework/security/web/webauthn/authentication/WebAuthnAuthenticationFilterTests.java

@@ -27,7 +27,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import org.skyscreamer.jsonassert.JSONAssert;
 
 import org.springframework.http.HttpStatus;
-import org.springframework.http.converter.GenericHttpMessageConverter;
+import org.springframework.http.converter.SmartHttpMessageConverter;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.mock.web.MockServletContext;
@@ -79,7 +79,7 @@ class WebAuthnAuthenticationFilterTests {
 			""";
 
 	@Mock
-	private GenericHttpMessageConverter<Object> converter;
+	private SmartHttpMessageConverter<Object> converter;
 
 	@Mock
 	private PublicKeyCredentialRequestOptionsRepository requestOptionsRepository;

+ 153 - 0
webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJackson2Tests.java

@@ -0,0 +1,153 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
+import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs;
+
+/**
+ * Test Jackson serialization of CredProtectAuthenticationExtensionsClientInput
+ *
+ * @author Rob Winch
+ */
+class CredProtectAuthenticationExtensionsClientInputJackson2Tests {
+
+	private ObjectMapper mapper;
+
+	@BeforeEach
+	void setup() {
+		this.mapper = new ObjectMapper();
+		this.mapper.registerModule(new WebauthnJackson2Module());
+	}
+
+	@Test
+	void writeAuthenticationExtensionsClientInputsWhenCredProtectUserVerificationOptional() throws Exception {
+		String expected = """
+					{
+						"credentialProtectionPolicy": "userVerificationOptional",
+						"enforceCredentialProtectionPolicy": true
+					}
+				""";
+
+		CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect(
+				CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL,
+				true);
+		CredProtectAuthenticationExtensionsClientInput credProtectInput = new CredProtectAuthenticationExtensionsClientInput(
+				credProtect);
+		ImmutableAuthenticationExtensionsClientInputs clientInputs = new ImmutableAuthenticationExtensionsClientInputs(
+				credProtectInput);
+
+		String actual = this.mapper.writeValueAsString(clientInputs);
+
+		JSONAssert.assertEquals(expected, actual, false);
+	}
+
+	@Test
+	void writeAuthenticationExtensionsClientInputsWhenCredProtectUserVerificationOptionalWithCredentialIdList()
+			throws Exception {
+		String expected = """
+					{
+						"credentialProtectionPolicy": "userVerificationOptionalWithCredentialIdList",
+						"enforceCredentialProtectionPolicy": true
+					}
+				""";
+
+		CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect(
+				CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL_WITH_CREDENTIAL_ID_LIST,
+				true);
+		CredProtectAuthenticationExtensionsClientInput credProtectInput = new CredProtectAuthenticationExtensionsClientInput(
+				credProtect);
+		ImmutableAuthenticationExtensionsClientInputs clientInputs = new ImmutableAuthenticationExtensionsClientInputs(
+				credProtectInput);
+
+		String actual = this.mapper.writeValueAsString(clientInputs);
+
+		JSONAssert.assertEquals(expected, actual, false);
+	}
+
+	@Test
+	void writeAuthenticationExtensionsClientInputsWhenCredProtectUserVerificationRequired() throws Exception {
+		String expected = """
+					{
+						"credentialProtectionPolicy": "userVerificationRequired",
+						"enforceCredentialProtectionPolicy": true
+					}
+				""";
+
+		CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect(
+				CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_REQUIRED,
+				true);
+		CredProtectAuthenticationExtensionsClientInput credProtectInput = new CredProtectAuthenticationExtensionsClientInput(
+				credProtect);
+		ImmutableAuthenticationExtensionsClientInputs clientInputs = new ImmutableAuthenticationExtensionsClientInputs(
+				credProtectInput);
+
+		String actual = this.mapper.writeValueAsString(clientInputs);
+
+		JSONAssert.assertEquals(expected, actual, false);
+	}
+
+	@Test
+	void writeAuthenticationExtensionsClientInputsWhenEnforceCredentialProtectionPolicyTrue() throws Exception {
+		String expected = """
+					{
+						"credentialProtectionPolicy": "userVerificationOptional",
+						"enforceCredentialProtectionPolicy": true
+					}
+				""";
+
+		CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect(
+				CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL,
+				true);
+		CredProtectAuthenticationExtensionsClientInput credProtectInput = new CredProtectAuthenticationExtensionsClientInput(
+				credProtect);
+		ImmutableAuthenticationExtensionsClientInputs clientInputs = new ImmutableAuthenticationExtensionsClientInputs(
+				credProtectInput);
+
+		String actual = this.mapper.writeValueAsString(clientInputs);
+
+		JSONAssert.assertEquals(expected, actual, false);
+	}
+
+	@Test
+	void writeAuthenticationExtensionsClientInputsWhenEnforceCredentialProtectionPolicyFalse() throws Exception {
+		String expected = """
+					{
+						"credentialProtectionPolicy": "userVerificationOptional",
+						"enforceCredentialProtectionPolicy": false
+					}
+				""";
+
+		CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect(
+				CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL,
+				false);
+		CredProtectAuthenticationExtensionsClientInput credProtectInput = new CredProtectAuthenticationExtensionsClientInput(
+				credProtect);
+		ImmutableAuthenticationExtensionsClientInputs clientInputs = new ImmutableAuthenticationExtensionsClientInputs(
+				credProtectInput);
+
+		String actual = this.mapper.writeValueAsString(clientInputs);
+
+		JSONAssert.assertEquals(expected, actual, false);
+	}
+
+}

+ 3 - 4
webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/CredProtectAuthenticationExtensionsClientInputJacksonTests.java

@@ -16,10 +16,10 @@
 
 package org.springframework.security.web.webauthn.jackson;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.skyscreamer.jsonassert.JSONAssert;
+import tools.jackson.databind.json.JsonMapper;
 
 import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
 import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs;
@@ -31,12 +31,11 @@ import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExte
  */
 class CredProtectAuthenticationExtensionsClientInputJacksonTests {
 
-	private ObjectMapper mapper;
+	private JsonMapper mapper;
 
 	@BeforeEach
 	void setup() {
-		this.mapper = new ObjectMapper();
-		this.mapper.registerModule(new WebauthnJackson2Module());
+		this.mapper = JsonMapper.builder().addModule(new WebauthnJacksonModule()).build();
 	}
 
 	@Test

+ 363 - 0
webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/Jackson2Tests.java

@@ -0,0 +1,363 @@
+/*
+ * Copyright 2004-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.webauthn.jackson;
+
+import java.time.Duration;
+import java.util.Arrays;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
+import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
+import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
+import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
+import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
+import org.springframework.security.web.webauthn.api.Bytes;
+import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
+import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput;
+import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs;
+import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs;
+import org.springframework.security.web.webauthn.api.PublicKeyCredential;
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
+import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
+import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions;
+import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class Jackson2Tests {
+
+	private ObjectMapper mapper;
+
+	@BeforeEach
+	void setup() {
+		this.mapper = new ObjectMapper();
+		this.mapper.registerModule(new WebauthnJackson2Module());
+	}
+
+	@Test
+	void readAuthenticatorTransport() throws Exception {
+		AuthenticatorTransport transport = this.mapper.readValue("\"hybrid\"", AuthenticatorTransport.class);
+
+		assertThat(transport).isEqualTo(AuthenticatorTransport.HYBRID);
+	}
+
+	@Test
+	void readAuthenticatorAttachment() throws Exception {
+		AuthenticatorAttachment value = this.mapper.readValue("\"cross-platform\"", AuthenticatorAttachment.class);
+		assertThat(value).isEqualTo(AuthenticatorAttachment.CROSS_PLATFORM);
+	}
+
+	@Test
+	void writeAuthenticatorAttachment() throws Exception {
+		String value = this.mapper.writeValueAsString(AuthenticatorAttachment.CROSS_PLATFORM);
+		assertThat(value).isEqualTo("\"cross-platform\"");
+	}
+
+	@Test
+	void readAuthenticationExtensionsClientOutputs() throws Exception {
+		String json = """
+				{
+					"credProps": {
+						"rk": false
+					}
+				}
+				""";
+		ImmutableAuthenticationExtensionsClientOutputs clientExtensionResults = new ImmutableAuthenticationExtensionsClientOutputs(
+				new CredentialPropertiesOutput(false));
+
+		AuthenticationExtensionsClientOutputs outputs = this.mapper.readValue(json,
+				AuthenticationExtensionsClientOutputs.class);
+		assertThat(outputs).usingRecursiveComparison().isEqualTo(clientExtensionResults);
+	}
+
+	@Test
+	void readAuthenticationExtensionsClientOutputsWhenAuthenticatorDisplayName() throws Exception {
+		String json = """
+				{
+					"credProps": {
+						"rk": false,
+						"authenticatorDisplayName": "1Password"
+					}
+				}
+				""";
+		ImmutableAuthenticationExtensionsClientOutputs clientExtensionResults = new ImmutableAuthenticationExtensionsClientOutputs(
+				new CredentialPropertiesOutput(false));
+
+		AuthenticationExtensionsClientOutputs outputs = this.mapper.readValue(json,
+				AuthenticationExtensionsClientOutputs.class);
+		assertThat(outputs).usingRecursiveComparison().isEqualTo(clientExtensionResults);
+	}
+
+	@Test
+	void readCredPropsWhenAuthenticatorDisplayName() throws Exception {
+		String json = """
+				{
+					"rk": false,
+					"authenticatorDisplayName": "1Password"
+				}
+				""";
+		CredentialPropertiesOutput credProps = new CredentialPropertiesOutput(false);
+
+		CredentialPropertiesOutput outputs = this.mapper.readValue(json, CredentialPropertiesOutput.class);
+		assertThat(outputs).usingRecursiveComparison().isEqualTo(credProps);
+	}
+
+	@Test
+	void readAuthenticationExtensionsClientOutputsWhenFieldAfter() throws Exception {
+		String json = """
+				{
+					"clientOutputs": {
+						"credProps": {
+							"rk": false
+						}
+					},
+					"label": "Cell Phone"
+				}
+				""";
+		ImmutableAuthenticationExtensionsClientOutputs clientExtensionResults = new ImmutableAuthenticationExtensionsClientOutputs(
+				new CredentialPropertiesOutput(false));
+
+		ClassWithOutputsAndAnotherField expected = new ClassWithOutputsAndAnotherField();
+		expected.setClientOutputs(clientExtensionResults);
+		expected.setLabel("Cell Phone");
+
+		ClassWithOutputsAndAnotherField actual = this.mapper.readValue(json, ClassWithOutputsAndAnotherField.class);
+		assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
+	}
+
+	@Test
+	void writePublicKeyCredentialCreationOptions() throws Exception {
+		String expected = """
+				{
+				    "attestation": "none",
+				    "authenticatorSelection": {
+				        "residentKey": "required"
+				    },
+				    "challenge": "q7lCdd3SVQxdC-v8pnRAGEn1B2M-t7ZECWPwCAmhWvc",
+				    "excludeCredentials": [],
+				    "extensions": {
+				        "credProps": true
+				    },
+				    "pubKeyCredParams": [
+				        {
+				            "alg": -7,
+				            "type": "public-key"
+				        },{
+				            "alg": -8,
+				            "type": "public-key"
+				        },
+				        {
+				            "alg": -257,
+				            "type": "public-key"
+				        }
+				    ],
+				    "rp": {
+				        "id": "example.localhost",
+				        "name": "SimpleWebAuthn Example"
+				    },
+				    "timeout": 300000,
+				    "user": {
+				        "displayName": "user@example.localhost",
+				        "id": "oWJtkJ6vJ_m5b84LB4_K7QKTCTEwLIjCh4tFMCGHO4w",
+				        "name": "user@example.localhost"
+				    }
+				}
+				""";
+
+		PublicKeyCredentialCreationOptions options = TestPublicKeyCredentialCreationOptions
+			.createPublicKeyCredentialCreationOptions()
+			.build();
+
+		String string = this.mapper.writeValueAsString(options);
+
+		JSONAssert.assertEquals(expected, string, false);
+	}
+
+	@Test
+	void readPublicKeyCredentialAuthenticatorAttestationResponse() throws Exception {
+
+		PublicKeyCredential<AuthenticatorAttestationResponse> publicKeyCredential = this.mapper.readValue(
+				PublicKeyCredentialJson.PUBLIC_KEY_JSON,
+				new TypeReference<PublicKeyCredential<AuthenticatorAttestationResponse>>() {
+				});
+
+		ImmutableAuthenticationExtensionsClientOutputs clientExtensionResults = new ImmutableAuthenticationExtensionsClientOutputs(
+				new CredentialPropertiesOutput(false));
+
+		PublicKeyCredential<AuthenticatorAttestationResponse> expected = PublicKeyCredential.builder()
+			.id("AX6nVVERrH6opMafUGn3Z9EyNEy6cftfBKV_2YxYl1jdW8CSJxMKGXFV3bnrKTiMSJeInkG7C6B2lPt8E5i3KaM")
+			.rawId(Bytes
+				.fromBase64("AX6nVVERrH6opMafUGn3Z9EyNEy6cftfBKV_2YxYl1jdW8CSJxMKGXFV3bnrKTiMSJeInkG7C6B2lPt8E5i3KaM"))
+			.response(AuthenticatorAttestationResponse.builder()
+				.attestationObject(Bytes.fromBase64(
+						"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjFSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQF-p1VREax-qKTGn1Bp92fRMjRMunH7XwSlf9mMWJdY3VvAkicTChlxVd256yk4jEiXiJ5BuwugdpT7fBOYtymjpQECAyYgASFYIJK-2epPEw0ujHN-gvVp2Hp3ef8CzU3zqwO5ylx8L2OsIlggK5x5OlTGEPxLS-85TAABum4aqVK4CSWJ7LYDdkjuBLk"))
+				.clientDataJSON(Bytes.fromBase64(
+						"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiSUJRbnVZMVowSzFIcUJvRldDcDJ4bEpsOC1vcV9hRklYenlUX0YwLTBHVSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0"))
+				.transports(AuthenticatorTransport.HYBRID, AuthenticatorTransport.INTERNAL)
+				.build())
+			.type(PublicKeyCredentialType.PUBLIC_KEY)
+			.clientExtensionResults(clientExtensionResults)
+			.authenticatorAttachment(AuthenticatorAttachment.CROSS_PLATFORM)
+			.build();
+
+		assertThat(publicKeyCredential).usingRecursiveComparison().isEqualTo(expected);
+	}
+
+	@Test
+	void readPublicKeyCredentialAuthenticatorAttestationResponseWhenExtraFields() throws Exception {
+		final String json = """
+				{
+					 "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjFSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQF-p1VREax-qKTGn1Bp92fRMjRMunH7XwSlf9mMWJdY3VvAkicTChlxVd256yk4jEiXiJ5BuwugdpT7fBOYtymjpQECAyYgASFYIJK-2epPEw0ujHN-gvVp2Hp3ef8CzU3zqwO5ylx8L2OsIlggK5x5OlTGEPxLS-85TAABum4aqVK4CSWJ7LYDdkjuBLk",
+					 "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiSUJRbnVZMVowSzFIcUJvRldDcDJ4bEpsOC1vcV9hRklYenlUX0YwLTBHVSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
+					 "transports": [
+					   "hybrid",
+					   "internal"
+					 ],
+					 "publicKeyAlgorithm": -7,
+					 "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkr7Z6k8TDS6Mc36C9WnYend5_wLNTfOrA7nKXHwvY6wrnHk6VMYQ_EtL7zlMAAG6bhqpUrgJJYnstgN2SO4EuQ",
+					 "authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQF-p1VREax-qKTGn1Bp92fRMjRMunH7XwSlf9mMWJdY3VvAkicTChlxVd256yk4jEiXiJ5BuwugdpT7fBOYtymjpQECAyYgASFYIJK-2epPEw0ujHN-gvVp2Hp3ef8CzU3zqwO5ylx8L2OsIlggK5x5OlTGEPxLS-85TAABum4aqVK4CSWJ7LYDdkjuBLk"
+				}
+				""";
+		AuthenticatorAttestationResponse response = this.mapper.readValue(json, AuthenticatorAttestationResponse.class);
+
+		ImmutableAuthenticationExtensionsClientOutputs clientExtensionResults = new ImmutableAuthenticationExtensionsClientOutputs(
+				new CredentialPropertiesOutput(false));
+
+		AuthenticatorAttestationResponse expected = AuthenticatorAttestationResponse.builder()
+			.attestationObject(Bytes.fromBase64(
+					"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjFSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQF-p1VREax-qKTGn1Bp92fRMjRMunH7XwSlf9mMWJdY3VvAkicTChlxVd256yk4jEiXiJ5BuwugdpT7fBOYtymjpQECAyYgASFYIJK-2epPEw0ujHN-gvVp2Hp3ef8CzU3zqwO5ylx8L2OsIlggK5x5OlTGEPxLS-85TAABum4aqVK4CSWJ7LYDdkjuBLk"))
+			.clientDataJSON(Bytes.fromBase64(
+					"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiSUJRbnVZMVowSzFIcUJvRldDcDJ4bEpsOC1vcV9hRklYenlUX0YwLTBHVSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0"))
+			.transports(AuthenticatorTransport.HYBRID, AuthenticatorTransport.INTERNAL)
+			.build();
+
+		assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+	}
+
+	@Test
+	void writeAuthenticationOptions() throws Exception {
+		PublicKeyCredentialRequestOptions credentialRequestOptions = PublicKeyCredentialRequestOptions.builder()
+			.allowCredentials(Arrays.asList())
+			.challenge(Bytes.fromBase64("I69THX904Q8ONhCgUgOu2PCQCcEjTDiNmokdbgsAsYU"))
+			.rpId("example.localhost")
+			.timeout(Duration.ofMinutes(5))
+			.userVerification(UserVerificationRequirement.REQUIRED)
+			.build();
+		String actual = this.mapper.writeValueAsString(credentialRequestOptions);
+
+		String expected = """
+						{
+				    "challenge": "I69THX904Q8ONhCgUgOu2PCQCcEjTDiNmokdbgsAsYU",
+				    "allowCredentials": [],
+				    "timeout": 300000,
+				    "userVerification": "required",
+				    "rpId": "example.localhost"
+				  }
+
+				""";
+		JSONAssert.assertEquals(expected, actual, false);
+	}
+
+	@Test
+	void readPublicKeyCredentialAuthenticatorAssertionResponse() throws Exception {
+		String json = """
+					{
+					   "id": "IquGb208Fffq2cROa1ZxMg",
+					   "rawId": "IquGb208Fffq2cROa1ZxMg",
+					   "response": {
+						 "authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MdAAAAAA",
+						 "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaDB2Z3dHUWpvQ3pBekRVc216UHBrLUpWSUpSUmduMEw0S1ZTWU5SY0VaYyIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
+						 "signature": "MEUCIAdfzPAn3voyXynwa0IXk1S0envMY5KP3NEe9aj4B2BuAiEAm_KJhQoWXdvfhbzwACU3NM4ltQe7_Il46qFUwtpuTdg",
+						 "userHandle": "oWJtkJ6vJ_m5b84LB4_K7QKTCTEwLIjCh4tFMCGHO4w"
+					   },
+					   "type": "public-key",
+					   "clientExtensionResults": {},
+					   "authenticatorAttachment": "cross-platform"
+					 }
+				""";
+		PublicKeyCredential<AuthenticatorAssertionResponse> publicKeyCredential = this.mapper.readValue(json,
+				new TypeReference<PublicKeyCredential<AuthenticatorAssertionResponse>>() {
+				});
+
+		ImmutableAuthenticationExtensionsClientOutputs clientExtensionResults = new ImmutableAuthenticationExtensionsClientOutputs();
+
+		PublicKeyCredential<AuthenticatorAssertionResponse> expected = PublicKeyCredential.builder()
+			.id("IquGb208Fffq2cROa1ZxMg")
+			.rawId(Bytes.fromBase64("IquGb208Fffq2cROa1ZxMg"))
+			.response(AuthenticatorAssertionResponse.builder()
+				.authenticatorData(Bytes.fromBase64("SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MdAAAAAA"))
+				.clientDataJSON(Bytes.fromBase64(
+						"eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaDB2Z3dHUWpvQ3pBekRVc216UHBrLUpWSUpSUmduMEw0S1ZTWU5SY0VaYyIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0"))
+				.signature(Bytes.fromBase64(
+						"MEUCIAdfzPAn3voyXynwa0IXk1S0envMY5KP3NEe9aj4B2BuAiEAm_KJhQoWXdvfhbzwACU3NM4ltQe7_Il46qFUwtpuTdg"))
+				.userHandle(Bytes.fromBase64("oWJtkJ6vJ_m5b84LB4_K7QKTCTEwLIjCh4tFMCGHO4w"))
+				.build())
+			.type(PublicKeyCredentialType.PUBLIC_KEY)
+			.clientExtensionResults(clientExtensionResults)
+			.authenticatorAttachment(AuthenticatorAttachment.CROSS_PLATFORM)
+			.build();
+
+		assertThat(publicKeyCredential).usingRecursiveComparison().isEqualTo(expected);
+	}
+
+	@Test
+	void writeAuthenticationExtensionsClientInputsWhenCredPropsTrue() throws Exception {
+		String expected = """
+					{
+						"credProps": true
+					}
+				""";
+
+		ImmutableAuthenticationExtensionsClientInputs clientInputs = new ImmutableAuthenticationExtensionsClientInputs(
+				ImmutableAuthenticationExtensionsClientInput.credProps);
+
+		String actual = this.mapper.writeValueAsString(clientInputs);
+
+		JSONAssert.assertEquals(expected, actual, false);
+	}
+
+	public static class ClassWithOutputsAndAnotherField {
+
+		private String label;
+
+		private AuthenticationExtensionsClientOutputs clientOutputs;
+
+		public String getLabel() {
+			return this.label;
+		}
+
+		public void setLabel(String label) {
+			this.label = label;
+		}
+
+		public AuthenticationExtensionsClientOutputs getClientOutputs() {
+			return this.clientOutputs;
+		}
+
+		public void setClientOutputs(AuthenticationExtensionsClientOutputs clientOutputs) {
+			this.clientOutputs = clientOutputs;
+		}
+
+	}
+
+}

+ 4 - 5
webauthn/src/test/java/org/springframework/security/web/webauthn/jackson/JacksonTests.java

@@ -19,11 +19,11 @@ package org.springframework.security.web.webauthn.jackson;
 import java.time.Duration;
 import java.util.Arrays;
 
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.skyscreamer.jsonassert.JSONAssert;
+import tools.jackson.core.type.TypeReference;
+import tools.jackson.databind.json.JsonMapper;
 
 import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
 import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
@@ -46,12 +46,11 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 class JacksonTests {
 
-	private ObjectMapper mapper;
+	private JsonMapper mapper;
 
 	@BeforeEach
 	void setup() {
-		this.mapper = new ObjectMapper();
-		this.mapper.registerModule(new WebauthnJackson2Module());
+		this.mapper = JsonMapper.builder().addModule(new WebauthnJacksonModule()).build();
 	}
 
 	@Test

+ 4 - 5
webauthn/src/test/java/org/springframework/security/web/webauthn/registration/WebAuthnRegistrationRequestJacksonTests.java

@@ -16,9 +16,9 @@
 
 package org.springframework.security.web.webauthn.registration;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import tools.jackson.databind.json.JsonMapper;
 
 import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
 import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
@@ -29,7 +29,7 @@ import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExte
 import org.springframework.security.web.webauthn.api.PublicKeyCredential;
 import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
 import org.springframework.security.web.webauthn.jackson.PublicKeyCredentialJson;
-import org.springframework.security.web.webauthn.jackson.WebauthnJackson2Module;
+import org.springframework.security.web.webauthn.jackson.WebauthnJacksonModule;
 import org.springframework.security.web.webauthn.management.RelyingPartyPublicKey;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -40,12 +40,11 @@ import static org.assertj.core.api.Assertions.assertThat;
  */
 class WebAuthnRegistrationRequestJacksonTests {
 
-	private ObjectMapper mapper;
+	private JsonMapper mapper;
 
 	@BeforeEach
 	void setup() {
-		this.mapper = new ObjectMapper();
-		this.mapper.registerModule(new WebauthnJackson2Module());
+		this.mapper = JsonMapper.builder().addModule(new WebauthnJacksonModule()).build();
 	}
 
 	@Test