From 7f1700d043f62db4cec8fb7fcdd32e8f01fcd1ca Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 10 Jul 2026 17:41:21 -0600 Subject: [PATCH] Improve Equivalence Tests This commit adds equals and hashCode implementations as well as a readResolve implementation to ensure that deserialization mechanisms can correctly assess the equality of a constnat and a corresponding deserialized instance. For defense-in-depth reasons, this commit also favors .equals over == for these constants. Signed-off-by: Josh Cummings <3627351+jzheaux@users.noreply.github.com> --- .../webauthn/api/AuthenticatorTransport.java | 22 ++++++ .../webauthn/api/PublicKeyCredentialType.java | 22 ++++++ .../api/UserVerificationRequirement.java | 33 ++++++++ .../Webauthn4JRelyingPartyOperations.java | 11 ++- .../api/AuthenticatorAttachmentTests.java | 42 ++++++++++ .../api/AuthenticatorTransportTests.java | 76 +++++++++++++++++++ .../PublicKeyCredentialDescriptorTests.java | 49 ++++++++++++ ...ublicKeyCredentialRequestOptionsTests.java | 43 +++++++++++ .../api/PublicKeyCredentialTypeTests.java | 51 +++++++++++++ .../webauthn/api/SerializationTestUtils.java | 47 ++++++++++++ .../api/UserVerificationRequirementTests.java | 58 ++++++++++++++ 11 files changed, 448 insertions(+), 6 deletions(-) create mode 100644 webauthn/src/test/java/org/springframework/security/web/webauthn/api/AuthenticatorAttachmentTests.java create mode 100644 webauthn/src/test/java/org/springframework/security/web/webauthn/api/AuthenticatorTransportTests.java create mode 100644 webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialDescriptorTests.java create mode 100644 webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialRequestOptionsTests.java create mode 100644 webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialTypeTests.java create mode 100644 webauthn/src/test/java/org/springframework/security/web/webauthn/api/SerializationTestUtils.java create mode 100644 webauthn/src/test/java/org/springframework/security/web/webauthn/api/UserVerificationRequirementTests.java diff --git a/webauthn/src/main/java/org/springframework/security/web/webauthn/api/AuthenticatorTransport.java b/webauthn/src/main/java/org/springframework/security/web/webauthn/api/AuthenticatorTransport.java index a4633edad5..225ee78b5b 100644 --- a/webauthn/src/main/java/org/springframework/security/web/webauthn/api/AuthenticatorTransport.java +++ b/webauthn/src/main/java/org/springframework/security/web/webauthn/api/AuthenticatorTransport.java @@ -16,6 +16,7 @@ package org.springframework.security.web.webauthn.api; +import java.io.ObjectStreamException; import java.io.Serial; import java.io.Serializable; @@ -121,4 +122,25 @@ public final class AuthenticatorTransport implements Serializable { return new AuthenticatorTransport[] { USB, NFC, BLE, HYBRID, INTERNAL }; } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof AuthenticatorTransport other)) { + return false; + } + return this.value.equals(other.value); + } + + @Override + public int hashCode() { + return this.value.hashCode(); + } + + @Serial + private Object readResolve() throws ObjectStreamException { + return valueOf(this.value); + } + } diff --git a/webauthn/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialType.java b/webauthn/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialType.java index 9012b42178..5b1b2adc31 100644 --- a/webauthn/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialType.java +++ b/webauthn/src/main/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialType.java @@ -16,6 +16,7 @@ package org.springframework.security.web.webauthn.api; +import java.io.ObjectStreamException; import java.io.Serial; import java.io.Serializable; @@ -58,4 +59,25 @@ public final class PublicKeyCredentialType implements Serializable { return new PublicKeyCredentialType(value); } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof PublicKeyCredentialType other)) { + return false; + } + return this.value.equals(other.value); + } + + @Override + public int hashCode() { + return this.value.hashCode(); + } + + @Serial + private Object readResolve() throws ObjectStreamException { + return valueOf(this.value); + } + } diff --git a/webauthn/src/main/java/org/springframework/security/web/webauthn/api/UserVerificationRequirement.java b/webauthn/src/main/java/org/springframework/security/web/webauthn/api/UserVerificationRequirement.java index fccf62fbec..71b819e1ab 100644 --- a/webauthn/src/main/java/org/springframework/security/web/webauthn/api/UserVerificationRequirement.java +++ b/webauthn/src/main/java/org/springframework/security/web/webauthn/api/UserVerificationRequirement.java @@ -16,9 +16,12 @@ package org.springframework.security.web.webauthn.api; +import java.io.ObjectStreamException; import java.io.Serial; import java.io.Serializable; +import org.jspecify.annotations.Nullable; + /** * UserVerificationRequirement @@ -72,4 +75,34 @@ public final class UserVerificationRequirement implements Serializable { return this.value; } + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof UserVerificationRequirement other)) { + return false; + } + return this.value.equals(other.value); + } + + @Override + public int hashCode() { + return this.value.hashCode(); + } + + @Serial + private Object readResolve() throws ObjectStreamException { + switch (this.value) { + case "required": + return REQUIRED; + case "preferred": + return PREFERRED; + case "discouraged": + return DISCOURAGED; + default: + return this; + } + } + } diff --git a/webauthn/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java b/webauthn/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java index 205a403e2e..f4bb48e28a 100644 --- a/webauthn/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java +++ b/webauthn/src/main/java/org/springframework/security/web/webauthn/management/Webauthn4JRelyingPartyOperations.java @@ -257,8 +257,8 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe byte[] clientDataJSON = response.getClientDataJSON().getBytes(); Challenge challenge = new DefaultChallenge(base64Challenge); ServerProperty serverProperty = new ServerProperty(origins, rpId, challenge); - boolean userVerificationRequired = creationOptions.getAuthenticatorSelection() - .getUserVerification() == UserVerificationRequirement.REQUIRED; + boolean userVerificationRequired = UserVerificationRequirement.REQUIRED + .equals(creationOptions.getAuthenticatorSelection().getUserVerification()); // requireUserPresence The constant Boolean value true // https://www.w3.org/TR/webauthn-3/#sctn-op-make-cred boolean userPresenceRequired = true; @@ -317,8 +317,7 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe private com.webauthn4j.data.PublicKeyCredentialParameters convertParamToWebauthn4j( PublicKeyCredentialParameters parameter) { - PublicKeyCredentialType credentialType = PublicKeyCredentialType.valueOf(parameter.getType().getValue()); - if (credentialType != PublicKeyCredentialType.PUBLIC_KEY) { + if (!PublicKeyCredentialType.PUBLIC_KEY.equals(parameter.getType())) { throw new IllegalArgumentException( "Cannot convert unknown credential type " + parameter.getType() + " to webauthn4j"); } @@ -394,8 +393,8 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe String rpId = requestOptions.getRpId(); Assert.notNull(rpId, "rpId cannot be null"); ServerProperty serverProperty = new ServerProperty(origins, rpId, challenge); - boolean userVerificationRequired = request.getRequestOptions() - .getUserVerification() == UserVerificationRequirement.REQUIRED; + boolean userVerificationRequired = UserVerificationRequirement.REQUIRED + .equals(request.getRequestOptions().getUserVerification()); com.webauthn4j.data.AuthenticationRequest authenticationRequest = new com.webauthn4j.data.AuthenticationRequest( request.getPublicKey().getRawId().getBytes(), assertionResponse.getAuthenticatorData().getBytes(), diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/api/AuthenticatorAttachmentTests.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/AuthenticatorAttachmentTests.java new file mode 100644 index 0000000000..09771d632a --- /dev/null +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/AuthenticatorAttachmentTests.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.api; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Verifies that {@link AuthenticatorAttachment} correctly restores singleton identity + * after Java deserialization. This class already implements {@code readResolve()} and + * serves as the reference for the pattern required by the other pseudo-enum types. + */ +class AuthenticatorAttachmentTests { + + @Test + void platformWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(AuthenticatorAttachment.PLATFORM)) + .isSameAs(AuthenticatorAttachment.PLATFORM); + } + + @Test + void crossPlatformWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(AuthenticatorAttachment.CROSS_PLATFORM)) + .isSameAs(AuthenticatorAttachment.CROSS_PLATFORM); + } + +} diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/api/AuthenticatorTransportTests.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/AuthenticatorTransportTests.java new file mode 100644 index 0000000000..1a8a2688ba --- /dev/null +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/AuthenticatorTransportTests.java @@ -0,0 +1,76 @@ +/* + * 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.api; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class AuthenticatorTransportTests { + + @Test + void usbWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(AuthenticatorTransport.USB)) + .isSameAs(AuthenticatorTransport.USB); + } + + @Test + void nfcWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(AuthenticatorTransport.NFC)) + .isSameAs(AuthenticatorTransport.NFC); + } + + @Test + void bleWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(AuthenticatorTransport.BLE)) + .isSameAs(AuthenticatorTransport.BLE); + } + + @Test + void smartCardWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(AuthenticatorTransport.SMART_CARD)) + .isSameAs(AuthenticatorTransport.SMART_CARD); + } + + @Test + void hybridWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(AuthenticatorTransport.HYBRID)) + .isSameAs(AuthenticatorTransport.HYBRID); + } + + @Test + void internalWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(AuthenticatorTransport.INTERNAL)) + .isSameAs(AuthenticatorTransport.INTERNAL); + } + + @Test + void usbWhenSameValueThenEquals() { + assertThat(new AuthenticatorTransport("usb")).isEqualTo(AuthenticatorTransport.USB); + } + + @Test + void usbWhenSameValueThenHashCodeMatches() { + assertThat(new AuthenticatorTransport("usb")).hasSameHashCodeAs(AuthenticatorTransport.USB); + } + + @Test + void usbWhenDifferentValueThenNotEquals() { + assertThat(AuthenticatorTransport.USB).isNotEqualTo(AuthenticatorTransport.NFC); + } + +} diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialDescriptorTests.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialDescriptorTests.java new file mode 100644 index 0000000000..c21eb584f6 --- /dev/null +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialDescriptorTests.java @@ -0,0 +1,49 @@ +/* + * 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.api; + +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PublicKeyCredentialDescriptorTests { + + @Test + void typeWhenDeserializedThenSameAsConstant() { + PublicKeyCredentialDescriptor descriptor = PublicKeyCredentialDescriptor.builder() + .id(TestBytes.get()) + .type(PublicKeyCredentialType.PUBLIC_KEY) + .build(); + PublicKeyCredentialDescriptor deserialized = SerializationTestUtils.serializeAndDeserialize(descriptor); + assertThat(deserialized.getType()).isSameAs(PublicKeyCredentialType.PUBLIC_KEY); + } + + @Test + void transportsWhenDeserializedThenSameAsConstants() { + PublicKeyCredentialDescriptor descriptor = PublicKeyCredentialDescriptor.builder() + .id(TestBytes.get()) + .type(PublicKeyCredentialType.PUBLIC_KEY) + .transports(Set.of(AuthenticatorTransport.USB, AuthenticatorTransport.HYBRID)) + .build(); + PublicKeyCredentialDescriptor deserialized = SerializationTestUtils.serializeAndDeserialize(descriptor); + assertThat(deserialized.getTransports()).containsExactlyInAnyOrder(AuthenticatorTransport.USB, + AuthenticatorTransport.HYBRID); + } + +} diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialRequestOptionsTests.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialRequestOptionsTests.java new file mode 100644 index 0000000000..826fd2349b --- /dev/null +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialRequestOptionsTests.java @@ -0,0 +1,43 @@ +/* + * 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.api; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PublicKeyCredentialRequestOptionsTests { + + @Test + void userVerificationRequiredWhenDeserializedThenSameAsConstant() { + PublicKeyCredentialRequestOptions options = TestPublicKeyCredentialRequestOptions.create() + .userVerification(UserVerificationRequirement.REQUIRED) + .build(); + PublicKeyCredentialRequestOptions deserialized = SerializationTestUtils.serializeAndDeserialize(options); + assertThat(deserialized.getUserVerification()).isSameAs(UserVerificationRequirement.REQUIRED); + } + + @Test + void userVerificationPreferredWhenDeserializedThenSameAsConstant() { + PublicKeyCredentialRequestOptions options = TestPublicKeyCredentialRequestOptions.create() + .userVerification(UserVerificationRequirement.PREFERRED) + .build(); + PublicKeyCredentialRequestOptions deserialized = SerializationTestUtils.serializeAndDeserialize(options); + assertThat(deserialized.getUserVerification()).isSameAs(UserVerificationRequirement.PREFERRED); + } + +} diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialTypeTests.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialTypeTests.java new file mode 100644 index 0000000000..a1feccec3f --- /dev/null +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/PublicKeyCredentialTypeTests.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.api; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PublicKeyCredentialTypeTests { + + @Test + void publicKeyWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(PublicKeyCredentialType.PUBLIC_KEY)) + .isSameAs(PublicKeyCredentialType.PUBLIC_KEY); + } + + @Test + void publicKeyWhenSameValueThenEquals() { + PublicKeyCredentialType first = PublicKeyCredentialType.valueOf("custom"); + PublicKeyCredentialType second = PublicKeyCredentialType.valueOf("custom"); + assertThat(first).isEqualTo(second); + } + + @Test + void publicKeyWhenSameValueThenHashCodeMatches() { + PublicKeyCredentialType first = PublicKeyCredentialType.valueOf("custom"); + PublicKeyCredentialType second = PublicKeyCredentialType.valueOf("custom"); + assertThat(first).hasSameHashCodeAs(second); + } + + @Test + void publicKeyWhenDifferentValueThenNotEquals() { + assertThat(PublicKeyCredentialType.valueOf("custom-1")) + .isNotEqualTo(PublicKeyCredentialType.valueOf("custom-2")); + } + +} diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/api/SerializationTestUtils.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/SerializationTestUtils.java new file mode 100644 index 0000000000..1bbb1ffe4c --- /dev/null +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/SerializationTestUtils.java @@ -0,0 +1,47 @@ +/* + * 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.api; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +public final class SerializationTestUtils { + + private SerializationTestUtils() { + } + + @SuppressWarnings("unchecked") + public static T serializeAndDeserialize(T object) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(object); + } + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + try (ObjectInputStream ois = new ObjectInputStream(bais)) { + return (T) ois.readObject(); + } + } + catch (Exception ex) { + throw new RuntimeException("Serialization round-trip failed", ex); + } + } + +} diff --git a/webauthn/src/test/java/org/springframework/security/web/webauthn/api/UserVerificationRequirementTests.java b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/UserVerificationRequirementTests.java new file mode 100644 index 0000000000..615f557e1a --- /dev/null +++ b/webauthn/src/test/java/org/springframework/security/web/webauthn/api/UserVerificationRequirementTests.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.api; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class UserVerificationRequirementTests { + + @Test + void requiredWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(UserVerificationRequirement.REQUIRED)) + .isSameAs(UserVerificationRequirement.REQUIRED); + } + + @Test + void preferredWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(UserVerificationRequirement.PREFERRED)) + .isSameAs(UserVerificationRequirement.PREFERRED); + } + + @Test + void discouragedWhenDeserializedThenSameAsConstant() { + assertThat(SerializationTestUtils.serializeAndDeserialize(UserVerificationRequirement.DISCOURAGED)) + .isSameAs(UserVerificationRequirement.DISCOURAGED); + } + + @Test + void requiredWhenSameValueThenEquals() { + assertThat(new UserVerificationRequirement("required")).isEqualTo(UserVerificationRequirement.REQUIRED); + } + + @Test + void requiredWhenSameValueThenHashCodeMatches() { + assertThat(new UserVerificationRequirement("required")).hasSameHashCodeAs(UserVerificationRequirement.REQUIRED); + } + + @Test + void requiredWhenDifferentValueThenNotEquals() { + assertThat(UserVerificationRequirement.REQUIRED).isNotEqualTo(UserVerificationRequirement.PREFERRED); + } + +}