Describe the bug
As a Serializable class, DefaultSaml2AuthenticatedPrincipal should define serialVersionUID to avoid unnecessarily breaking compatibility across versions.
To Reproduce
Serialise a DefaultSaml2AuthenticatedPrincipal using Spring Security 6.3.5 and then deserialzie using 6.4.1.
Expected behavior
The field layout of the classes has not changed so they should be compatible, but the methods have (equalsand hashCode were added), which changes the auto-generated serialVersionUID.
Comment From: Rednas92-spec
Hi,
We had this issue when upgrading to Spring Boot 3.4.0 . When a user had a session prior upgrade; it will throw following stack trace after upgrade:
2024-12-06T13:11:38.676Z ERROR [-,,,ONBEKEND] 1 --- [nio-8000-exec-1] o.a.c.c.C.[Tomcat].[localhost] : Exception Processing [ErrorPage[errorCode=0, location=/error]]
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [byte[]] to type [java.lang.Object] for value [{...}]
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47) ~[spring-core-6.1.14.jar:6.1.14]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:182) ~[spring-core-6.1.14.jar:6.1.14]
at org.springframework.session.jdbc.JdbcIndexedSessionRepository.deserialize(JdbcIndexedSessionRepository.java:689) ~[spring-session-jdbc-3.3.3.jar:3.3.3]
at org.springframework.session.jdbc.JdbcIndexedSessionRepository$SessionResultSetExtractor.lambda$extractData$0(JdbcIndexedSessionRepository.java:977) ~[spring-session-jdbc-3.3.3.jar:3.3.3]
at org.springframework.session.jdbc.JdbcIndexedSessionRepository$4.get(JdbcIndexedSessionRepository.java:721) ~[spring-session-jdbc-3.3.3.jar:3.3.3]
at org.springframework.session.jdbc.JdbcIndexedSessionRepository$JdbcSession.getAttribute(JdbcIndexedSessionRepository.java:801) ~[spring-session-jdbc-3.3.3.jar:3.3.3]
at org.springframework.session.PrincipalNameIndexResolver.resolveIndexValueFor(PrincipalNameIndexResolver.java:55) ~[spring-session-core-3.3.3.jar:3.3.3]
at org.springframework.session.SingleIndexResolver.resolveIndexesFor(SingleIndexResolver.java:48) ~[spring-session-core-3.3.3.jar:3.3.3]
at org.springframework.session.DelegatingIndexResolver.resolveIndexesFor(DelegatingIndexResolver.java:49) ~[spring-session-core-3.3.3.jar:3.3.3]
at org.springframework.session.jdbc.JdbcIndexedSessionRepository$JdbcSession.lambda$save$11(JdbcIndexedSessionRepository.java:913) ~[spring-session-jdbc-3.3.3.jar:3.3.3]
at org.springframework.transaction.support.TransactionOperations.lambda$executeWithoutResult$0(TransactionOperations.java:68) ~[spring-tx-6.1.14.jar:6.1.14]
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-6.1.14.jar:6.1.14]
at org.springframework.transaction.support.TransactionOperations.executeWithoutResult(TransactionOperations.java:67) ~[spring-tx-6.1.14.jar:6.1.14]
at org.springframework.session.jdbc.JdbcIndexedSessionRepository$JdbcSession.save(JdbcIndexedSessionRepository.java:910) ~[spring-session-jdbc-3.3.3.jar:3.3.3]
at org.springframework.session.jdbc.JdbcIndexedSessionRepository.save(JdbcIndexedSessionRepository.java:477) ~[spring-session-jdbc-3.3.3.jar:3.3.3]
at org.springframework.session.jdbc.JdbcIndexedSessionRepository.save(JdbcIndexedSessionRepository.java:141) ~[spring-session-jdbc-3.3.3.jar:3.3.3]
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:229) ~[spring-session-core-3.3.3.jar:3.3.3]
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:145) ~[spring-session-core-3.3.3.jar:3.3.3]
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82) ~[spring-session-core-3.3.3.jar:3.3.3]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:362) ~[spring-web-6.1.14.jar:6.1.14]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:278) ~[spring-web-6.1.14.jar:6.1.14]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101) ~[spring-web-6.1.14.jar:6.1.14]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:632) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:410) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:330) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:267) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:362) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:222) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:308) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:149) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:731) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:384) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.31.jar:10.1.31]
at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:80) ~[spring-core-6.1.14.jar:6.1.14]
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:37) ~[spring-core-6.1.14.jar:6.1.14]
at org.springframework.core.convert.support.GenericConversionService$ConverterAdapter.convert(GenericConversionService.java:358) ~[spring-core-6.1.14.jar:6.1.14]
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41) ~[spring-core-6.1.14.jar:6.1.14]
... 46 common frames omitted
Caused by: java.io.InvalidClassException: org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal; local class incompatible: stream classdesc serialVersionUID = -7601324133433139825, local class serialVersionUID = 1067069248264210993
at java.base/java.io.ObjectStreamClass.initNonProxy(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readNonProxyDesc(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readClassDesc(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream$FieldValues.<init>(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream$FieldValues.<init>(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readSerialData(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readObject0(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readObject(Unknown Source) ~[na:na]
at java.base/java.io.ObjectInputStream.readObject(Unknown Source) ~[na:na]
at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:71) ~[spring-core-6.1.14.jar:6.1.14]
at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:75) ~[spring-core-6.1.14.jar:6.1.14]
... 49 common frames omitted
The user sesion was corrupted. We had to remove all sessions from database. Maybe I can make a contribution setting serialVersionUID to -7601324133433139825 (new serialVersionUID ) so this will not happen in future upgrades?
Tx, Sander