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>