diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/AttestationConveyancePreference.java b/web/src/main/java/org/springframework/security/web/webauthn/api/AttestationConveyancePreference.java
index 41164faf491..fa65ae1dced 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/AttestationConveyancePreference.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/AttestationConveyancePreference.java
@@ -16,6 +16,9 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
+
/**
* WebAuthn Relying
* Parties may use client extension
* input entry in the {@link AuthenticationExtensionsClientInputs}.
@@ -25,7 +27,7 @@
* @since 6.4
* @see ImmutableAuthenticationExtensionsClientInput
*/
-public interface AuthenticationExtensionsClientInput {
+public interface AuthenticationExtensionsClientInput extends Serializable {
/**
* Gets the extension
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/AuthenticationExtensionsClientInputs.java b/web/src/main/java/org/springframework/security/web/webauthn/api/AuthenticationExtensionsClientInputs.java
index 44a26a41c12..acd9513af18 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/AuthenticationExtensionsClientInputs.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/AuthenticationExtensionsClientInputs.java
@@ -16,6 +16,7 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serializable;
import java.util.List;
/**
@@ -31,7 +32,7 @@
* @since 6.4
* @see PublicKeyCredentialCreationOptions#getExtensions()
*/
-public interface AuthenticationExtensionsClientInputs {
+public interface AuthenticationExtensionsClientInputs extends Serializable {
/**
* Gets all of the {@link AuthenticationExtensionsClientInput}.
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/AuthenticatorSelectionCriteria.java b/web/src/main/java/org/springframework/security/web/webauthn/api/AuthenticatorSelectionCriteria.java
index 6ff7c98600e..46b4b35da9a 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/AuthenticatorSelectionCriteria.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/AuthenticatorSelectionCriteria.java
@@ -16,6 +16,9 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
+
/**
* AuthenticatorAttachment
@@ -31,7 +34,10 @@
* @since 6.4
* @see PublicKeyCredentialCreationOptions#getAuthenticatorSelection()
*/
-public final class AuthenticatorSelectionCriteria {
+public final class AuthenticatorSelectionCriteria implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 6295924992300524641L;
private final AuthenticatorAttachment authenticatorAttachment;
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/Bytes.java b/web/src/main/java/org/springframework/security/web/webauthn/api/Bytes.java
index 6fbcc3596c6..b8270577e46 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/Bytes.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/Bytes.java
@@ -16,6 +16,8 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
@@ -28,7 +30,10 @@
* @author Rob Winch
* @since 6.4
*/
-public final class Bytes {
+public final class Bytes implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -3278138671365709777L;
private static final SecureRandom RANDOM = new SecureRandom();
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/COSEAlgorithmIdentifier.java b/web/src/main/java/org/springframework/security/web/webauthn/api/COSEAlgorithmIdentifier.java
index 0cafd9309bd..49847fa4f56 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/COSEAlgorithmIdentifier.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/COSEAlgorithmIdentifier.java
@@ -16,6 +16,9 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
+
/**
* COSEAlgorithmIdentifier is
@@ -25,7 +28,10 @@
* @since 6.4
* @see PublicKeyCredentialParameters#getAlg()
*/
-public final class COSEAlgorithmIdentifier {
+public final class COSEAlgorithmIdentifier implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -7174114312834239069L;
public static final COSEAlgorithmIdentifier EdDSA = new COSEAlgorithmIdentifier(-8);
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/CredProtectAuthenticationExtensionsClientInput.java b/web/src/main/java/org/springframework/security/web/webauthn/api/CredProtectAuthenticationExtensionsClientInput.java
index 22372717595..d315281ab6a 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/CredProtectAuthenticationExtensionsClientInput.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/CredProtectAuthenticationExtensionsClientInput.java
@@ -16,6 +16,9 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
+
/**
* Implements
@@ -27,6 +30,9 @@
public class CredProtectAuthenticationExtensionsClientInput
implements AuthenticationExtensionsClientInput {
+ @Serial
+ private static final long serialVersionUID = -6418175591005843455L;
+
private final CredProtect input;
public CredProtectAuthenticationExtensionsClientInput(CredProtect input) {
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutableAuthenticationExtensionsClientInput.java b/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutableAuthenticationExtensionsClientInput.java
index eb656c3cdfb..0a28258703f 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutableAuthenticationExtensionsClientInput.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutableAuthenticationExtensionsClientInput.java
@@ -16,6 +16,8 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+
/**
* An immutable {@link AuthenticationExtensionsClientInput}.
*
@@ -26,6 +28,9 @@
*/
public class ImmutableAuthenticationExtensionsClientInput implements AuthenticationExtensionsClientInput {
+ @Serial
+ private static final long serialVersionUID = -1738152485672656808L;
+
/**
* https://www.w3.org/TR/webauthn-3/#sctn-authenticator-credential-properties-extension
*/
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutableAuthenticationExtensionsClientInputs.java b/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutableAuthenticationExtensionsClientInputs.java
index cef29f378a5..1482beee579 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutableAuthenticationExtensionsClientInputs.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutableAuthenticationExtensionsClientInputs.java
@@ -16,6 +16,7 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
import java.util.Arrays;
import java.util.List;
@@ -27,6 +28,9 @@
*/
public class ImmutableAuthenticationExtensionsClientInputs implements AuthenticationExtensionsClientInputs {
+ @Serial
+ private static final long serialVersionUID = 4277817521578485720L;
+
private final List inputs;
public ImmutableAuthenticationExtensionsClientInputs(List inputs) {
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutablePublicKeyCredentialUserEntity.java b/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutablePublicKeyCredentialUserEntity.java
index 7374f8fd6e9..c5ffdbcbd00 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutablePublicKeyCredentialUserEntity.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/ImmutablePublicKeyCredentialUserEntity.java
@@ -16,6 +16,8 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+
/**
* PublicKeyCredentialUserEntity
@@ -28,6 +30,9 @@
*/
public final class ImmutablePublicKeyCredentialUserEntity implements PublicKeyCredentialUserEntity {
+ @Serial
+ private static final long serialVersionUID = -3438693960347279759L;
+
/**
* When inherited by PublicKeyCredentialUserEntity, it is a human-palatable identifier
* for a user account. It is intended only for display, i.e., aiding the user in
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialCreationOptions.java b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialCreationOptions.java
index 2bbdcb9b2b0..1ad47bdee27 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialCreationOptions.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialCreationOptions.java
@@ -16,6 +16,8 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
@@ -32,7 +34,10 @@
* @author Rob Winch
* @since 6.4
*/
-public final class PublicKeyCredentialCreationOptions {
+public final class PublicKeyCredentialCreationOptions implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -8805501645775760774L;
private final PublicKeyCredentialRpEntity rp;
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialDescriptor.java b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialDescriptor.java
index ad454814b0f..d4bb1a87dcf 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialDescriptor.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialDescriptor.java
@@ -16,6 +16,8 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
import java.util.Set;
/**
@@ -29,7 +31,10 @@
* @author Rob Winch
* @since 6.4
*/
-public final class PublicKeyCredentialDescriptor {
+public final class PublicKeyCredentialDescriptor implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 8793385059692676240L;
private final PublicKeyCredentialType type;
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialParameters.java b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialParameters.java
index abb8c028330..8e7f3241ad0 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialParameters.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialParameters.java
@@ -16,6 +16,9 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
+
/**
* The PublicKeyCredentialParameters
@@ -25,7 +28,10 @@
* @since 6.4
* @see PublicKeyCredentialCreationOptions#getPubKeyCredParams()
*/
-public final class PublicKeyCredentialParameters {
+public final class PublicKeyCredentialParameters implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 8471974877710173696L;
public static final PublicKeyCredentialParameters EdDSA = new PublicKeyCredentialParameters(
COSEAlgorithmIdentifier.EdDSA);
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialRpEntity.java b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialRpEntity.java
index d8e7de80141..65723385163 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialRpEntity.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialRpEntity.java
@@ -16,6 +16,9 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
+
/**
* The PublicKeyCredentialRpEntity
@@ -25,7 +28,10 @@
* @author Rob Winch
* @since 6.4
*/
-public final class PublicKeyCredentialRpEntity {
+public final class PublicKeyCredentialRpEntity implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -5219081524858472915L;
private final String name;
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialType.java b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialType.java
index 57f1c6ec463..1efcb45254d 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialType.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialType.java
@@ -16,6 +16,9 @@
package org.springframework.security.web.webauthn.api;
+import java.io.Serial;
+import java.io.Serializable;
+
/**
* The PublicKeyCredentialType
@@ -24,7 +27,10 @@
* @author Rob Winch
* @since 6.4
*/
-public final class PublicKeyCredentialType {
+public final class PublicKeyCredentialType implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 7025333122210061679L;
/**
* The only credential type that currently exists.
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialUserEntity.java b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialUserEntity.java
index f5da998fd83..cade3a009c8 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialUserEntity.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialUserEntity.java
@@ -19,6 +19,8 @@
import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations;
+import java.io.Serializable;
+
/**
* PublicKeyCredentialUserEntity
@@ -30,7 +32,7 @@
* @since 6.4
* @see WebAuthnRelyingPartyOperations#authenticate(RelyingPartyAuthenticationRequest)
*/
-public interface PublicKeyCredentialUserEntity {
+public interface PublicKeyCredentialUserEntity extends Serializable {
/**
* The ResidentKeyRequirement
@@ -24,7 +27,10 @@
* @author Rob Winch
* @since 6.4
*/
-public final class ResidentKeyRequirement {
+public final class ResidentKeyRequirement implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 2047716518193458797L;
/**
* The UserVerificationRequirement
@@ -24,7 +27,10 @@
* @author Rob Winch
* @since 6.4
*/
-public final class UserVerificationRequirement {
+public final class UserVerificationRequirement implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = -2801001231345540040L;
/**
* The {
+ @Serial
+ private static final long serialVersionUID = -5579815774497047153L;
+
/**
* Creates a new instance.
*/
diff --git a/web/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java b/web/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java
index e1983079fc9..a7c368ec279 100644
--- a/web/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java
+++ b/web/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java
@@ -290,7 +290,7 @@ private List convertCredentia
private com.webauthn4j.data.PublicKeyCredentialParameters convertParamToWebauthn4j(
PublicKeyCredentialParameters parameter) {
- if (parameter.getType() != PublicKeyCredentialType.PUBLIC_KEY) {
+ if (!PublicKeyCredentialType.PUBLIC_KEY.getValue().equals(parameter.getType().getValue())) {
throw new IllegalArgumentException(
"Cannot convert unknown credential type " + parameter.getType() + " to webauthn4j");
}
diff --git a/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java b/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java
index dc597918354..25f6aa2a111 100644
--- a/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java
+++ b/web/src/test/java/org/springframework/security/web/webauthn/management/Webauthn4jRelyingPartyOperationsTests.java
@@ -16,6 +16,10 @@
package org.springframework.security.web.webauthn.management;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Arrays;
@@ -60,6 +64,7 @@
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity;
import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
+import org.springframework.util.SerializationUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -494,6 +499,30 @@ void createCredentialRequestOptionsThenUserVerificationSameAsCreation() {
.isEqualTo(creationOptions.getAuthenticatorSelection().getUserVerification());
}
+ @Test
+ void convertParamToWebauthn4jPublicKeyComparison() throws Exception {
+
+ PublicKeyCredentialCreationOptions options = TestPublicKeyCredentialCreationOptions
+ .createPublicKeyCredentialCreationOptions()
+ .build();
+
+ // Simulate storage into external session storage: serialize/deserialize of the creation options
+ ByteArrayOutputStream bo = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bo);
+ oos.writeObject(options);
+
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bo.toByteArray()));
+ PublicKeyCredentialCreationOptions copiedOptions = (PublicKeyCredentialCreationOptions)ois.readObject() ;
+
+ // Check that the deep copied options are still valid
+ PublicKeyCredential publicKey = TestPublicKeyCredential.createPublicKeyCredential().build();
+ ImmutableRelyingPartyRegistrationRequest registrationRequest = new ImmutableRelyingPartyRegistrationRequest(
+ copiedOptions, new RelyingPartyPublicKey(publicKey, this.label));
+
+ // Should not throw an exception
+ this.rpOperations.registerCredential(registrationRequest);
+ }
+
private static AuthenticatorAttestationResponse setFlag(byte... flags) throws Exception {
AuthenticatorAttestationResponseBuilder authAttResponseBldr = TestAuthenticatorAttestationResponse
.createAuthenticatorAttestationResponse();