spring-security-kerberos
spring-security-kerberos copied to clipboard
NotSerializableException on JaasSubjectHolder
Summary
With version 2.0.0
a serialization exception is introduced.
Explanation
The org.springframework.security.kerberos.authentication.KerberosServiceRequestToken
extends the AbstractAuthenticationToken
which implements Authentication
(extends Serializable
).
The KerberosServiceRequestToken
holds an org.springframework.security.kerberos.authentication.JaasSubjectHolder
which is not Serializable
(and the field is not transient). And therefore (in our case) spring-session-jdbc throws a NotSerializableException
while trying to serialize the object.
Spring session jdbc tries to store the SecurityContextImpl
which extends Serializable
(refer to SecurityContextImpl docs)
The SecurityContextImpl
holds a org.springframework.security.core.Authentication
object (in our case the KerberosServiceRequestToken
.
Suggestion
The field private JaasSubjectHolder jaasSubjectHolder
on KerberosServiceRequestToken
should be transient or the Object JaasSubjectHolder
should extends Serializable
. I'm not sure about the actual solution and implication on the rest.
Have the exact same problem with Spring Boot 3.1.1/Security;6.1.1/Kerberos:2.0.0
Same problem here:
Describe the bug spring-security-kerberos-core, 2.0.0 introduced org.springframework.security.kerberos.authentication.JaasSubjectHolder.
This object wasn't in spring-security-kerberos-core, 1.0.1-RELEASE version, which used other object:
- Class org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider was not using JaasSubjectHolder.
Since 2.0.0, KerberosAuthenticationProvider started using JaasSubjectHolder.
Therefore, if Spring Security session management stores object into session, it has to be Serializable. Especially, if session is backed by Redis, for example.
To Reproduce Use: .sessionManagement(management -> management .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
- store session in Redis.
Expected behavior No exception.
Sample No sample provided, quite obvious reasoning.
Stacktrace
org.springframework.data.redis.serializer.SerializationException: Cannot serialize
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:96)
at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:186)
at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:161)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.data.redis.core.BoundOperationsProxyFactory$BoundOperationsMethodInterceptor.doInvoke(BoundOperationsProxyFactory.java:183)
at org.springframework.data.redis.core.BoundOperationsProxyFactory$BoundOperationsMethodInterceptor.invoke(BoundOperationsProxyFactory.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:72)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244)
at jdk.proxy3/jdk.proxy3.$Proxy186.putAll(Unknown Source)
at org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession.saveDelta(RedisIndexedSessionRepository.java:852)
at org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession.save(RedisIndexedSessionRepository.java:840)
at org.springframework.session.data.redis.RedisIndexedSessionRepository.save(RedisIndexedSessionRepository.java:478)
at org.springframework.session.data.redis.RedisIndexedSessionRepository.save(RedisIndexedSessionRepository.java:258)
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:228)
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:146)
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:642)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:410)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:340)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:277)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:358)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:222)
at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:304)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:149)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:64)
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:33)
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:94)
... 47 common frames omitted
Caused by: java.io.NotSerializableException: org.springframework.security.kerberos.authentication.JaasSubjectHolder
at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1187)
at java.base/java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1572)
at java.base/java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1529)
at java.base/java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1438)
at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1181)
at java.base/java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1572)
at java.base/java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1529)
at java.base/java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1438)
at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1181)
at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:350)
at org.springframework.core.serializer.DefaultSerializer.serialize(DefaultSerializer.java:46)
at org.springframework.core.serializer.Serializer.serializeToByteArray(Serializer.java:56)
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:60)
... 49 common frames omitted
I've created a pull request with fix proposal. Hopefully it will work in all scenarios (I tried comparing all changes between 1.0.1-RELEASE and 2.0.0, and added also serialVersionUID to another class where it was missing).
BTW:
Until its merged, this is working for me:
<dependency>
<groupId>org.springframework.security.kerberos</groupId>
<artifactId>spring-security-kerberos-client</artifactId>
<version>2.0.0</version>
</dependency>
<!-- Hold on 1.0.1-RELEASE, version 2.0.0 waits for:
- https://github.com/spring-projects/spring-security-kerberos/issues/178
-->
<dependency>
<groupId>org.springframework.security.kerberos</groupId>
<artifactId>spring-security-kerberos-core</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.kerberos</groupId>
<artifactId>spring-security-kerberos-web</artifactId>
<version>2.0.0</version>
</dependency>