From 34afa64c0cf4f774d85db90df73187ebca028f4a Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 11:19:30 -0600 Subject: [PATCH 1/4] Add Current-Version Deserialization Test We should test that serialized files from the current minor version can be deserialized. This ensures that serializations remain deserializable in patch releases. Issue gh-3737 --- ...gSecurityCoreVersionSerializableTests.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index c4b96ab290..e8ee65af0a 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -690,7 +690,34 @@ class SpringSecurityCoreVersionSerializableTests { } @ParameterizedTest - @MethodSource("getFilesToDeserialize") + @MethodSource("getCurrentSerializedFiles") + void shouldBeAbleToDeserializeClassFromCurrentVersion(Path filePath) { + try (FileInputStream fileInputStream = new FileInputStream(filePath.toFile()); + ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) { + Object obj = objectInputStream.readObject(); + Class clazz = Class.forName(filePath.getFileName().toString().replace(".serialized", "")); + assertThat(obj).isInstanceOf(clazz); + } + catch (IOException | ClassNotFoundException ex) { + fail("Could not deserialize " + filePath, ex); + } + } + + static Stream getCurrentSerializedFiles() throws IOException { + assertThat(currentVersionFolder.toFile().exists()) + .as("Make sure that the " + currentVersionFolder + " exists and is not empty") + .isTrue(); + try (Stream files = Files.list(currentVersionFolder)) { + if (files.findFirst().isEmpty()) { + fail("Please make sure to run SpringSecurityCoreVersionSerializableTests#serializeCurrentVersionClasses for the " + + getPreviousVersion() + " version"); + } + } + return Files.list(currentVersionFolder); + } + + @ParameterizedTest + @MethodSource("getPreviousSerializedFiles") void shouldBeAbleToDeserializeClassFromPreviousVersion(Path filePath) { try (FileInputStream fileInputStream = new FileInputStream(filePath.toFile()); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) { @@ -703,7 +730,7 @@ class SpringSecurityCoreVersionSerializableTests { } } - static Stream getFilesToDeserialize() throws IOException { + static Stream getPreviousSerializedFiles() throws IOException { assertThat(previousVersionFolder.toFile().exists()) .as("Make sure that the " + previousVersionFolder + " exists and is not empty") .isTrue(); From 65d53beff8c3c5a58883c18ef1907d7f4b029aff Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 13:33:32 -0600 Subject: [PATCH 2/4] Polish Serialization Tests - Error when public, non-ignored, serializable file is missing a sample - Provide mechanism for creating an InstancioApi from scratch Issue gh-17038 --- ...gSecurityCoreVersionSerializableTests.java | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index e8ee65af0a..e053a6f730 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -16,6 +16,8 @@ package org.springframework.security; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -36,13 +38,17 @@ import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.UUID; +import java.util.function.Supplier; import java.util.stream.Stream; import jakarta.servlet.http.Cookie; +import org.apache.commons.lang3.ObjectUtils; import org.apereo.cas.client.validation.AssertionImpl; import org.instancio.Instancio; import org.instancio.InstancioApi; @@ -63,6 +69,7 @@ import org.springframework.mock.web.MockHttpSession; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.AuthorizationServiceException; import org.springframework.security.access.SecurityConfig; +import org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException; import org.springframework.security.access.intercept.RunAsUserToken; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AccountExpiredException; @@ -94,15 +101,19 @@ import org.springframework.security.authentication.event.LogoutSuccessEvent; import org.springframework.security.authentication.jaas.JaasAuthenticationToken; import org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent; import org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent; +import org.springframework.security.authentication.ott.DefaultOneTimeToken; import org.springframework.security.authentication.ott.InvalidOneTimeTokenException; import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken; import org.springframework.security.authentication.password.CompromisedPasswordException; import org.springframework.security.authorization.AuthorityAuthorizationDecision; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationDeniedException; +import org.springframework.security.authorization.event.AuthorizationEvent; +import org.springframework.security.authorization.event.AuthorizationGrantedEvent; import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken; import org.springframework.security.cas.authentication.CasAuthenticationToken; import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken; +import org.springframework.security.config.annotation.AlreadyBuiltException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; @@ -128,11 +139,14 @@ import org.springframework.security.oauth2.client.authentication.OAuth2Authoriza import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens; +import org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent; +import org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent; import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken; import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens; import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation; import org.springframework.security.oauth2.client.oidc.session.TestOidcSessionInformations; import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistration.ClientSettings; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.core.OAuth2AccessToken; @@ -148,6 +162,7 @@ import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipal import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; +import org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses; @@ -172,6 +187,7 @@ import org.springframework.security.oauth2.server.resource.BearerTokenErrors; import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; @@ -188,8 +204,10 @@ import org.springframework.security.saml2.provider.service.authentication.Saml2P import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens; import org.springframework.security.saml2.provider.service.authentication.TestSaml2Authentications; +import org.springframework.security.saml2.provider.service.authentication.TestSaml2LogoutRequests; import org.springframework.security.saml2.provider.service.authentication.TestSaml2PostAuthenticationRequests; import org.springframework.security.saml2.provider.service.authentication.TestSaml2RedirectAuthenticationRequests; +import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; @@ -213,6 +231,7 @@ import org.springframework.security.web.savedrequest.DefaultSavedRequest; import org.springframework.security.web.savedrequest.SimpleSavedRequest; import org.springframework.security.web.server.firewall.ServerExchangeRejectedException; import org.springframework.security.web.session.HttpSessionCreatedEvent; +import org.springframework.security.web.session.HttpSessionIdChangedEvent; import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs; import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs; import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse; @@ -234,7 +253,9 @@ import org.springframework.security.web.webauthn.api.TestAuthenticationAssertion import org.springframework.security.web.webauthn.api.TestBytes; import org.springframework.security.web.webauthn.api.TestPublicKeyCredential; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; +import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.UserVerificationRequirement; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; @@ -262,6 +283,8 @@ class SpringSecurityCoreVersionSerializableTests { private static final Map, Generator> generatorByClassName = new HashMap<>(); + private static final Map, Supplier>> instancioByClassName = new HashMap<>(); + static final long securitySerialVersionUid = SpringSecurityCoreVersion.SERIAL_VERSION_UID; static Path currentVersionFolder = Paths.get("src/test/resources/serialized/" + getCurrentVersion()); @@ -766,10 +789,18 @@ class SpringSecurityCoreVersionSerializableTests { || Arrays.asList(suppressWarnings.value()).contains("Serial"); if (!hasSerialVersion && !hasSerialIgnore) { classes.add(clazz); + continue; + } + boolean isReachable = Modifier.isPublic(clazz.getModifiers()); + boolean hasSampleSerialization = currentVersionFolder.resolve(clazz.getName() + ".serialized") + .toFile() + .exists(); + if (hasSerialVersion && isReachable && !hasSampleSerialization) { + classes.add(clazz); } } - assertThat(classes) - .describedAs("Found Serializable classes that are either missing a serialVersionUID or a @SuppressWarnings") + assertThat(classes).describedAs( + "Found Serializable classes that are either missing a serialVersionUID or a @SuppressWarnings or a sample serialized file") .isEmpty(); } @@ -796,6 +827,9 @@ class SpringSecurityCoreVersionSerializableTests { } private static InstancioApi instancioWithDefaults(Class clazz) { + if (instancioByClassName.containsKey(clazz)) { + return instancioByClassName.get(clazz).get(); + } InstancioOfClassApi instancio = Instancio.of(clazz); ResolvableType[] generics = ResolvableType.forClass(clazz).getGenerics(); for (ResolvableType type : generics) { From 39fdceab594e14897cef58dbf3feb790f1f56636 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 13:36:21 -0600 Subject: [PATCH 3/4] Add Missing Serializable Samples Issue gh-17038 --- ...gSecurityCoreVersionSerializableTests.java | 80 ++++++++++++------ ...s.CycleInRoleHierarchyException.serialized | Bin 0 -> 10740 bytes ...zation.event.AuthorizationEvent.serialized | Bin 0 -> 1603 bytes ...event.AuthorizationGrantedEvent.serialized | Bin 0 -> 1692 bytes ...nnotation.AlreadyBuiltException.serialized | Bin 0 -> 10715 bytes ...ssion.HttpSessionIdChangedEvent.serialized | Bin 0 -> 421 bytes ...ropertiesOutput$ExtensionOutput.serialized | Bin 0 -> 115 bytes 7 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.web.session.HttpSessionIdChangedEvent.serialized create mode 100644 config/src/test/resources/serialized/6.4.x/org.springframework.security.web.webauthn.api.CredentialPropertiesOutput$ExtensionOutput.serialized diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index e053a6f730..c9843c7ed6 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -16,8 +16,6 @@ package org.springframework.security; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -38,7 +36,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -48,7 +45,6 @@ import java.util.function.Supplier; import java.util.stream.Stream; import jakarta.servlet.http.Cookie; -import org.apache.commons.lang3.ObjectUtils; import org.apereo.cas.client.validation.AssertionImpl; import org.instancio.Instancio; import org.instancio.InstancioApi; @@ -139,14 +135,11 @@ import org.springframework.security.oauth2.client.authentication.OAuth2Authoriza import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthenticationTokens; import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens; -import org.springframework.security.oauth2.client.event.OAuth2AuthorizedClientRefreshedEvent; -import org.springframework.security.oauth2.client.oidc.authentication.event.OidcUserRefreshedEvent; import org.springframework.security.oauth2.client.oidc.authentication.logout.OidcLogoutToken; import org.springframework.security.oauth2.client.oidc.authentication.logout.TestOidcLogoutTokens; import org.springframework.security.oauth2.client.oidc.session.OidcSessionInformation; import org.springframework.security.oauth2.client.oidc.session.TestOidcSessionInformations; import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistration.ClientSettings; import org.springframework.security.oauth2.client.registration.TestClientRegistrations; import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.core.OAuth2AccessToken; @@ -162,7 +155,6 @@ import org.springframework.security.oauth2.core.TestOAuth2AuthenticatedPrincipal import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; -import org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests; import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses; @@ -187,7 +179,6 @@ import org.springframework.security.oauth2.server.resource.BearerTokenErrors; import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication; import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken; -import org.springframework.security.oauth2.server.resource.authentication.DPoPAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException; import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal; @@ -253,9 +244,7 @@ import org.springframework.security.web.webauthn.api.TestAuthenticationAssertion import org.springframework.security.web.webauthn.api.TestBytes; import org.springframework.security.web.webauthn.api.TestPublicKeyCredential; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntities; import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity; -import org.springframework.security.web.webauthn.api.TestPublicKeyCredentials; import org.springframework.security.web.webauthn.api.UserVerificationRequirement; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication; import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken; @@ -417,6 +406,9 @@ class SpringSecurityCoreVersionSerializableTests { generatorByClassName.put(OAuth2IntrospectionException.class, (r) -> new OAuth2IntrospectionException("message", new RuntimeException())); + // config + generatorByClassName.put(AlreadyBuiltException.class, (r) -> new AlreadyBuiltException("message")); + // core generatorByClassName.put(RunAsUserToken.class, (r) -> { RunAsUserToken token = new RunAsUserToken("key", user, "creds", user.getAuthorities(), @@ -508,6 +500,20 @@ class SpringSecurityCoreVersionSerializableTests { generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true)); generatorByClassName.put(AuthorityAuthorizationDecision.class, (r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER"))); + generatorByClassName.put(CycleInRoleHierarchyException.class, (r) -> new CycleInRoleHierarchyException()); + generatorByClassName.put(AuthorizationEvent.class, + (r) -> new AuthorizationEvent(new SerializableSupplier<>(authentication), "source", + new AuthorizationDecision(true))); + generatorByClassName.put(AuthorizationGrantedEvent.class, + (r) -> new AuthorizationGrantedEvent<>(new SerializableSupplier<>(authentication), "source", + new AuthorizationDecision(true))); + instancioByClassName.put(AuthorizationGrantedEvent.class, () -> { + InstancioOfClassApi instancio = Instancio.of(AuthorizationGrantedEvent.class); + instancio.withTypeParameters(String.class); + instancio.supply(Select.all(AuthorizationGrantedEvent.class), + generatorByClassName.get(AuthorizationGrantedEvent.class)); + return instancio; + }); // cas generatorByClassName.put(CasServiceTicketAuthenticationToken.class, (r) -> { @@ -561,6 +567,7 @@ class SpringSecurityCoreVersionSerializableTests { token.setDetails(details); return token; }); + generatorByClassName.put(Saml2LogoutRequest.class, (r) -> TestSaml2LogoutRequests.create()); // web generatorByClassName.put(AnonymousAuthenticationToken.class, (r) -> { @@ -616,20 +623,8 @@ class SpringSecurityCoreVersionSerializableTests { request.addPreferredLocale(Locale.ENGLISH); return new SimpleSavedRequest(new DefaultSavedRequest(request, new PortResolverImpl(), "continue")); }); - - // webauthn - generatorByClassName.put(Bytes.class, (r) -> TestBytes.get()); - generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class, - (r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build()); - generatorByClassName.put(WebAuthnAuthentication.class, (r) -> { - PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity() - .id(TestBytes.get()) - .build(); - List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); - WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities); - webAuthnAuthentication.setDetails(details); - return webAuthnAuthentication; - }); + generatorByClassName.put(HttpSessionIdChangedEvent.class, + (r) -> new HttpSessionIdChangedEvent(new MockHttpSession(), "1")); // webauthn CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect( @@ -686,6 +681,25 @@ class SpringSecurityCoreVersionSerializableTests { generatorByClassName.put(WebAuthnAuthenticationRequestToken.class, (r) -> requestToken); generatorByClassName.put(AuthenticatorAttachment.class, (r) -> AuthenticatorAttachment.PLATFORM); // @formatter:on + generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class, + (r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build()); + generatorByClassName.put(WebAuthnAuthentication.class, (r) -> { + PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity() + .id(TestBytes.get()) + .build(); + List authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); + WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities); + webAuthnAuthentication.setDetails(details); + return webAuthnAuthentication; + }); + // @formatter:on + generatorByClassName.put(CredentialPropertiesOutput.ExtensionOutput.class, + (r) -> new CredentialPropertiesOutput(true).getOutput()); + + // One-Time Token + DefaultOneTimeToken oneTimeToken = new DefaultOneTimeToken(UUID.randomUUID().toString(), "user", + Instant.now().plusSeconds(300)); + generatorByClassName.put(DefaultOneTimeToken.class, (t) -> oneTimeToken); } @ParameterizedTest @@ -862,4 +876,20 @@ class SpringSecurityCoreVersionSerializableTests { return String.join(".", parts); } + @SuppressWarnings("serial") + private static final class SerializableSupplier implements Supplier, Serializable { + + private final T value; + + SerializableSupplier(T value) { + this.value = value; + } + + @Override + public T get() { + return this.value; + } + + } + } diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.access.hierarchicalroles.CycleInRoleHierarchyException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..43d7d327459fd83c9d89098ee53f0a9643b66db0 GIT binary patch literal 10740 zcmeHNU2Gjk6`t!Pj$`sqQs=jE(oIr`x^dz(KXux~wVlMN;{;zPkhT=9_l~dE-n+Zm zo$L6979`q&Kva|>`cR>YAE62f1gM1u^_5geeSwEQ@Bl)ns1g#qAn||{!Z|auv$H?< z`kIC(;)n6<%$ak}eCN!WIWzaie!IKb{aOir?Pe_1Lz79ly>|OwNSd zp1i&11VR@OLVf_&-kw058(^)v_1eCpe|WKjbUjWwr~R;Iu~E|PIvyRb*QRJVM%LM` z6-8sdRiWWHI1A2b#TZ#zq0oWo4Pn1*?V5I6s!?^}t@E96@c@GIAUhbUdK(Y{!QhqoHTHW|exdh?pOmH7Byov+?IJ zwSC^sNKd{|O74=QsV?!nl=xT^i8Gd0aREv5azw*2c&Y2qiV|@t^l@$bAtMj8CXhO8 zgaxBUPtd6DGF_XaQk#?il{V*uu8iz1)J1knO;&*>c?F)A3hZm5fYSYpWrG7VvMJNT zxg(RU`n;axY_ZsdMK2>8s={`3+^^6pmRr}Y((y8U4h-odyGE zv=+F4maHjzAJW;pr4Z@I+7U)Ng;b5G<2^;R4r}XSpMW*SBMcp?haqeYGVt(-NTYZ# zxdVR?#vYoj%q6iQq|+`~E)EK`a)F1+LB9L?;b9oi>3H-0obogX>f``4A1dTCOkG-q z80A&djKutRx9V1)3^1~a?-o-Q?x>xIj+uRCzle7rz2i7Y-;!)6@f3tWMm{Dg2|L8; z6c(pd%DW}C*f%3*V)K| zY=C)Zo8-J#@m&qo)n$E)%fjLk7N3F*P0`_=i+gY0GSB2jZBLDwq_AiqxaCJy`A9~d zYzt{HH9wwu)e&xK)CSR%0DIJ^fL2MLt&m0Bb~Q(EWif)^a{@;A zIj0ca3XSa0!KG}X+Y86V+OXYNF2Ty@L`9`VBN)a2?=7UJTuW*{dnggd};fsl?x}smpkmIMP6AUj#5J$3s zB~BF&X{ghr70tofP5+eB+b*G&vz)-}A#&!a+b~imd;vD<>0(jK&EXX_2ZpseBQ02` z?D$nak`ZltYRir|8`!7upPWpm75a5AwIhiWDN1NVtrNOY7M<}oax>nTM^Wck$qc~H zlpj362^jgz63twObQBzzT9x=d0xv7j@FHmYA*6uw4yN>G+q5yJQGKfBr1rWGrJ7fk zsHX0I#xR|>Ad4Dqcvj7^bzPBrJ%`QjxKJ#(zvKyC;slKFjIf>96mPC5TaQk=_==G` zZ@QCXl2eT@27XrmI`+MkB+JqtjQ-dS@aXzB93Btw!y`Z5MGOpAGtcN;JHv*jTB6u0csUhtm)6gf$o>|v-= zGF(W&X$$W}U{hDk(!A>-3qWs}pf%X-;qZkJWNgv#FA%an5hDF4XHerD#08EsBP%7} z0(PZMZJPGjT`_H2_HT!1*`LxdXuw7SZmk9OKqU;@sF zt#2rzqLmM;4Ew)}#rLpiVnyr{Kx6IaSY(z`Nw)^}zga*82Ef)|V8NqNAy7+36WRT$ zKpfzRt?yv*(Qtwt0hufkYwsG-J+qK|?n@STUreO3CnxmN)QR{2wrEGI9D&G;uvwh% zu{Ix{wot^P$M|gGf*cw;2a%s(^XIX67K`U}f|s#{E1Br*Lev#+i2P8g4iw0V2gh8PMQ}c$G=C9mUxsu_B(j69tBdC`HZ#NjPm~d+KQ9eb zr2gO@n)!@Pq`L@@@II`4MF;8xw!pI@fA`E>k+-_xX_f`U%~P{3mG-2<&rzws$PzQ% zoD})owY|8bSophAxOUm5?nPXy?%6YNfe-Je)D*92BG-q@?2GVg1;}Y-a?#tOw^;Cx zxL_>qKv5!COTi*8bXyQSf_*$*2oCv-ICViRQul-(iLJ`RIf<9sI#g zJ&qglf)q9b)k&lHN{JC;k?~wx$dC9#Q52=w#OoXuBMjC6}1-WYv-%1Myu z8JH#i!OmTtrIflnVt$}2bqeJ1JN?DwmFtkpD~J?+jO=LA6Wg)W6HDxXr_q0d#NxNn zad-@ym#;wa!>D-A+}W&4g1=Ji=Y8mjnXHFg;IQvN0Cr;kKoQXaBqEPu@mMn=cn`&{ z$FUeHBtiokFg^a*DFJojUx!qjD6p74qrG$v%O<#)hs+Ug=^?JgjdE&T@wga66tacS z33rx~fyG|Eb2n&kOj{^<4Tj*wlP-vLAb#o-3x)T`=AFu(DREDOxbc?az*QC+v4p{j z6~L8{5r4yaP2Qf=?+LaRjfv$a?>+Hb`$l{thXuIMIBXhx=uwVP53IAKOa7Dx0sIXp zeL_>ZMKHmi%fS|ej{j+1HTvNyBl(neS{Bw-Tt*2mWUR0h324&8u&(6ADqNXdfD1DC zS(_*BzwrlFy2Yz}vJdlNP$U}!Dsrk-CqD7>t7Pe|fFb`mpz;|xd-!3XTQLW@gQ^`^ zz`@A2!ggh?6f8GD;1e3~tp%1F5u>$1{9TiHsOOdgEr#TPNRm{g03zEd&ey0VmWb^8f$< literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..568c4a3ac20bce16fcb82e8b004f27231125c6e3 GIT binary patch literal 1603 zcmb7EJ7^S96urCIWV3{PHKIbS60wjOv@}gVu8T4xA+syGis9|-%leY}<;|O95=o3A z_yHp*iXs+TiP~yuYatez+9I{4v9VF`zS&)7Him>uG4L+;bM86ky?2|?>~R=%ct!DC z&g{xGCl+0B_^jel!{xIG2Q^1|6~n zgUkqv1oUY$WS*$LV5U0l+lFkV>b~omjPgMZS~&H5QwSK+5R1A6i(1E`HegX3P)vp$ z1_KVqw_C?>Y(WD=E@xI@g}6(%eoWoTec4Dt;v8fIv#2MCG(!!c z-Or32w3c5d0Rk5w@#N*N%q!&Z@^(Y(xD`DlSFcfueADxkdq{##IU^>LTQX@LM|=J8 zNS&el(%}zp*V->2NDZ3jiRn`TJylLkVpr5Ew!y$fB;z|GX;eljc$C{H`2_Jil)Wq| zjfBfPv($$0OPZmwZ3d@hnLtc$4ptzoK}POoFqfEN0GZ3}1;KF16Py@go5|~Mj;+|a zaz_%HiqIZIPRkm!$us&=Fr*C*#0)m-m?kQP?4q;MWhw}(feqXQ5_B{YHcIvS3%2Ey z*))?h=FkYNe!lYiNZ2%CNXFVi)%HbQ zhB+sTvU_mjTi>%!tmj%(Sef}WiWB<>zpy6xod5PbAlO@+{J(a3ZWx`|;p zzAeTaI~%wR-BpCHD5g2atPJ(Wd>2nmQ(NlwpC3A7Lg`eX5nA1v#U=Lrc$ToF^}{nd z13%nnAkraHtBOVQo3}4D$+rSC&g`A5 zet9iIp++6cC7cL{NBm*isuv`N-atUdHQRCA<@%}uQgTZiJ+$NK+EuDO@wJiF(`jlj X`B1H&+OS&5T|na&Azi7u2wD3Fm7qFw literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.authorization.event.AuthorizationGrantedEvent.serialized new file mode 100644 index 0000000000000000000000000000000000000000..6d3ca9608f9cacaa523776a846715debb31b4d0c GIT binary patch literal 1692 zcmbtVO-vI}5T2GIG{~Q%L{0Dn#)H{LkCGUEtc_#?gtkV}Kwh^Ge6ZbJ-oAx`0nwPC zCSsz|Xp9GMMvXT;di7vDC}&JKD;FrJS2B@Ebd zQga3VL+J65ldpygX#QYRGuicq4v=ZXD36gQN9H#&GQzxaZfa{xk*p8trxL2)i`*R+gV zOZlp$N?IY`{5+Q~l91w3FcVeFnmmoI-OkELnW6N;;difA8!sS89cpKp>2U=IikzCv znv55*br&2&GPEO-YGt&H%cX^08fLDGe##N0fpBSinp@yMVbfQ(!H_&h3Cwh7UAd#x*pijZHHD#O6dEg#^PCP1bVkD~fwVz;g~9r5 z(?q3^U36Amjw>cgU<*zN2|5}G8>G6O87pt+#DpLzbm6LB&0QzneqU|zNspKqQP5J+ zhH`wn?OrZubEprNKaTx8;uj4W#MpjcwYH#2uas<_su!+*>3H&iJ*$DxIf%Gofs^GR zG#8;?oTP6@q7AfJc`e|ANQt~-^3oO{wu!v?KwY#}MB3&SXQdSF8+4X}=*WGh8vnk$4#afL>xcS;r~>@hqOEV90TMrYuI^K=C|1gce=1M4k!-2Z&<>2ij)0NroF zo2|jkwB#JK)*lZ)c(}Q8sfKn1W}MwSSDk-_>bLU_lT6t%;1A0dy+9b+3ksU9TDI*h vmPb_(p((L-&yKB2f2Gp5qtvo^I>QY?i)!uEM!ufi1~l#{)J+z@CCJ(zGiF^1 literal 0 HcmV?d00001 diff --git a/config/src/test/resources/serialized/6.4.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized b/config/src/test/resources/serialized/6.4.x/org.springframework.security.config.annotation.AlreadyBuiltException.serialized new file mode 100644 index 0000000000000000000000000000000000000000..d3344aeda54a287d2730736f895487bb3cf89a2f GIT binary patch literal 10715 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 L7?_H(D+(9^Dt9X> literal 0 HcmV?d00001 From c3c2bcd6b7240fee6d5bc9c90be2c9023badcc75 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 5 May 2025 12:19:55 -0600 Subject: [PATCH 4/4] Ignore Serialization in Test Components Since we don't need to ensure the serializability of test components across versions, we can ignore missing version UIDs when those test components aren't about testing Java serialization. Issue gh-17038 --- .../SpringSecurityCoreVersionSerializableTests.java | 10 ++-------- .../config/annotation/method/configuration/Authz.java | 1 + .../access/annotation/BusinessServiceImpl.java | 5 +---- .../ExpressionProtectedBusinessServiceImpl.java | 5 +---- .../access/annotation/Jsr250BusinessServiceImpl.java | 5 +---- 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java index c9843c7ed6..2712617475 100644 --- a/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java +++ b/config/src/test/java/org/springframework/security/SpringSecurityCoreVersionSerializableTests.java @@ -740,17 +740,11 @@ class SpringSecurityCoreVersionSerializableTests { } } - static Stream getCurrentSerializedFiles() throws IOException { + static Stream getCurrentSerializedFiles() throws Exception { assertThat(currentVersionFolder.toFile().exists()) .as("Make sure that the " + currentVersionFolder + " exists and is not empty") .isTrue(); - try (Stream files = Files.list(currentVersionFolder)) { - if (files.findFirst().isEmpty()) { - fail("Please make sure to run SpringSecurityCoreVersionSerializableTests#serializeCurrentVersionClasses for the " - + getPreviousVersion() + " version"); - } - } - return Files.list(currentVersionFolder); + return getClassesToSerialize().map((clazz) -> currentVersionFolder.resolve(clazz.getName() + ".serialized")); } @ParameterizedTest diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/Authz.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/Authz.java index 145f344d12..5b6c784c7f 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/Authz.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/Authz.java @@ -55,6 +55,7 @@ public class Authz { return Mono.just(checkResult(result)); } + @SuppressWarnings("serial") public static class AuthzResult extends AuthorizationDecision { public AuthzResult(boolean granted) { diff --git a/core/src/test/java/org/springframework/security/access/annotation/BusinessServiceImpl.java b/core/src/test/java/org/springframework/security/access/annotation/BusinessServiceImpl.java index 587e795f5a..1bcf1ba84d 100644 --- a/core/src/test/java/org/springframework/security/access/annotation/BusinessServiceImpl.java +++ b/core/src/test/java/org/springframework/security/access/annotation/BusinessServiceImpl.java @@ -16,18 +16,15 @@ package org.springframework.security.access.annotation; -import java.io.Serial; import java.util.ArrayList; import java.util.List; /** * @author Joe Scalise */ +@SuppressWarnings("serial") public class BusinessServiceImpl implements BusinessService { - @Serial - private static final long serialVersionUID = -4249394090237180795L; - @Override @Secured({ "ROLE_USER" }) public void someUserMethod1() { diff --git a/core/src/test/java/org/springframework/security/access/annotation/ExpressionProtectedBusinessServiceImpl.java b/core/src/test/java/org/springframework/security/access/annotation/ExpressionProtectedBusinessServiceImpl.java index 1ca226709b..1c6fd2a84e 100644 --- a/core/src/test/java/org/springframework/security/access/annotation/ExpressionProtectedBusinessServiceImpl.java +++ b/core/src/test/java/org/springframework/security/access/annotation/ExpressionProtectedBusinessServiceImpl.java @@ -16,7 +16,6 @@ package org.springframework.security.access.annotation; -import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -24,11 +23,9 @@ import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreFilter; +@SuppressWarnings("serial") public class ExpressionProtectedBusinessServiceImpl implements BusinessService { - @Serial - private static final long serialVersionUID = -3320014879907436606L; - @Override public void someAdminMethod() { } diff --git a/core/src/test/java/org/springframework/security/access/annotation/Jsr250BusinessServiceImpl.java b/core/src/test/java/org/springframework/security/access/annotation/Jsr250BusinessServiceImpl.java index 6d9f34ac61..4eba9445a6 100644 --- a/core/src/test/java/org/springframework/security/access/annotation/Jsr250BusinessServiceImpl.java +++ b/core/src/test/java/org/springframework/security/access/annotation/Jsr250BusinessServiceImpl.java @@ -16,7 +16,6 @@ package org.springframework.security.access.annotation; -import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -27,11 +26,9 @@ import jakarta.annotation.security.RolesAllowed; * @author Luke Taylor */ @PermitAll +@SuppressWarnings("serial") public class Jsr250BusinessServiceImpl implements BusinessService { - @Serial - private static final long serialVersionUID = -7550211450382764339L; - @Override @RolesAllowed("ROLE_USER") public void someUserMethod1() {