Skip to content

GenericScope.setSerializationId can cause serialization issues #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rwinch opened this issue Feb 26, 2016 · 7 comments
Closed

GenericScope.setSerializationId can cause serialization issues #93

rwinch opened this issue Feb 26, 2016 · 7 comments

Comments

@rwinch
Copy link

rwinch commented Feb 26, 2016

GenericScope.setSerializationId can cause serialization issues as illustrated in spring-projects/spring-session#395

The failure happens when trying to serialize Session Scoped beans because DefaultListableBeanFactory.serializationId has a different value from when the serialization takes place and when the deserialization takes place.

In Spring Cloud, the GenericScope.setSerializationId sets the serialization id. This means both RefreshScope and ThreadScope (which inherit from GenericScope) are impacted by this.

The default value is a UUID calculated from the bytes of the Spring Bean names. Unfortunately the calculation of the resulting id does not appear to be constant. When the same application is restarted, the UUID is still different than the previous id.

Ultimately, this can cause the following stacktrace:

2016-02-26 14:51:34.092 ERROR 51427 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.lang.IllegalStateException: Cannot deserialize BeanFactory with id application:9000: no factory registered for this id
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:41) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
    at org.springframework.data.redis.core.AbstractOperations.deserializeHashValue(AbstractOperations.java:316) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
    at org.springframework.data.redis.core.AbstractOperations.deserializeHashMap(AbstractOperations.java:277) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
    at org.springframework.data.redis.core.DefaultHashOperations.entries(DefaultHashOperations.java:227) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
    at org.springframework.data.redis.core.DefaultBoundHashOperations.entries(DefaultBoundHashOperations.java:101) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
    at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:233) ~[spring-session-1.0.2.RELEASE.jar:na]
    at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:220) ~[spring-session-1.0.2.RELEASE.jar:na]
    at org.springframework.session.data.redis.RedisOperationsSessionRepository.getSession(RedisOperationsSessionRepository.java:141) ~[spring-session-1.0.2.RELEASE.jar:na]
    at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getSession(SessionRepositoryFilter.java:276) ~[spring-session-1.0.2.RELEASE.jar:na]
    at org.springframework.web.context.request.ServletRequestAttributes.updateAccessedSessionAttributes(ServletRequestAttributes.java:255) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.context.request.AbstractRequestAttributes.requestCompleted(AbstractRequestAttributes.java:48) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:106) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:125) ~[spring-session-1.0.2.RELEASE.jar:na]
    at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:65) ~[spring-session-1.0.2.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:103) ~[spring-boot-actuator-1.3.2.RELEASE.jar:1.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:521) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_65]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_65]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_65]
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.lang.IllegalStateException: Cannot deserialize BeanFactory with id application:9000: no factory registered for this id
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:39) ~[spring-data-redis-1.6.2.RELEASE.jar:1.6.2.RELEASE]
    ... 49 common frames omitted
Caused by: java.lang.IllegalStateException: Cannot deserialize BeanFactory with id application:9000: no factory registered for this id
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$SerializedBeanFactoryReference.readResolve(DefaultListableBeanFactory.java:1428) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_65]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_65]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_65]
    at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_65]
    at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1104) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1807) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1706) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1344) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:500) ~[na:1.7.0_65]
    at org.springframework.aop.framework.AdvisedSupport.readObject(AdvisedSupport.java:557) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_65]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_65]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_65]
    at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_65]
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1893) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350) ~[na:1.7.0_65]
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) ~[na:1.7.0_65]
    at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:70) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:73) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    ... 51 common frames omitted

Demo

You can find an example for reproducing this in rwinch/tut-spring-security-and-angular-js. Use the following instructions:

  • Ensure all cookies for localhost are cleared out
  • Start up Redis instance
  • Start oauth2/resource oauth2/ui and oauth2/authserver/
  • open http://localhost:8080/
  • Authenticated with user / password

Use the following branches

Workaround

This can be worked around by creating a RefreshScope bean definition. For example:

@Bean
public static RefreshScope refreshScope() {
    RefreshScope refresh = new RefreshScope();
    refresh.setId("application:1");
    return refresh;
}
@dsyer
Copy link
Contributor

dsyer commented Feb 27, 2016

I'm not 100 percent sure I follow (and the steps to reproduce are a little unclear, since the GitHub repo is from a tutorial with dozens of apps). Is it broken when you put an object that is in @RefresScope in the session? Why would you do that?

@rwinch
Copy link
Author

rwinch commented Feb 28, 2016

@dsyer Sorry for being unclear.

I'm not 100 percent sure I follow (and the steps to reproduce are a little unclear, since the GitHub repo is from a tutorial with dozens of apps).

I updated the description. The issue is demonstrated by starting oauth2/resource oauth2/ui and oauth2/authserver/ (these are the apps that were modified in the branches that were mentioned)

Is it broken when you put an object that is in @RefresScope in the session? Why would you do that?

No. The application is broken because Spring Security OAuth uses Session Scope objects which means they are placed in session. Since the RefreshScope is changing the serialization id it breaks serialization deserialization of the session scope beans.

This can be seen if you try to use Spring Session & Spring Security OAuth across multiple applications when Spring Cloud is used in one application.

It can also be seen if you restart a Spring Cloud application that stores session scope bean using Spring Session since the id changes between restarts.

I should add that this isn't just Spring Session as it is generically JDK serialization/deserialization of the session scope objects when the serializationId is changed.

@dsyer
Copy link
Contributor

dsyer commented Feb 28, 2016

OK, I see. It's been a problem lurking there for a long time. Only when you start to share beans across jvms does it come to the surface (or rather between application contexts). I'm not sure what the solution should be because the intention was good (to find an ID that is not too unique so they can share beans), but contradicts some other requirements (namely to have a uniquely addressable context ID for discovery and message passing). I think the issue that you are seeing is caused by multiple components all trying to set the application context ID, and of course not agreeing on the best value.

I need to refresh my knowledge a bit about how that ID gets used. In principle though, I don't know why for this OAuth2 use case it should matter - the bits that you need in the session are only strings and primitives, so they should serialize nicely.

@dsyer
Copy link
Contributor

dsyer commented Feb 29, 2016

The sample app broken because it is passing cookies downstream from the gateway to the resource server, and it shouldn't need to do that because the authentication is via the OAuth2 token in this sample. The resource server fails when it tries to hydrate a session from redis that it doesn't need to know about. It works for me with Brixton snapshots because the gateway isn't passing the cookie downstream any more. It also works as is if you remove the redis and spring session dependencies from the resource server (they aren't needed anyway, so that's perfectly acceptable in this case).

As far as the general issue goes with GenericScope I couldn't find any problem with the serialization ID in a single application (as opposed to multiple, manifestly different application contexts). So it seems like the bean names are deterministic and the ID is a decent enough representation of the context. My worries above about context IDs was unfounded: the serialization ID is, in principle, distinct from the application context ID (which we need for message passing etc.), and when you use RefreshScope it is, in fact, distinct, even though without RefreshScope they might have been the same. Whether or not the ID is actually needed to serialize the OAuth2 context bits is another question, and one that probably deserves a bit more thought and analysis.

On that last point, it is worth noting that Spring only uses the serialization ID for scoped proxies (which also means anything in @RefreshScope, but that isn't relevant to the issue here). Thus you can have a @Scope("session") bean that is not a proxy (via @Lazy and proxyMode=TARGET_CLASS) and it is serializable cleanly. Applications can use beans that are in @Scope("session") but not proxied by injecting ObjectFactory<X> instead of X, or by using the BeanFactory API to lookup the bean explicitly at runtime. The beans in question are defined by a library (Spring OAuth2) in this case so the user doesn't have a lot of choice. We could consider changing the OAuth2 library, but it would be a large enough change that we would need to wait for 3.0, I guess.

We could also ask the question of Spring Core, if it might be possible to use scoped proxies that are somehow marked as serializable "naturally" (i.e. without needing the BeanFactory to deserialize). In this case (and others, I should think) the beans that are serialized are just data holders, and the scope is being used to keep instances separate from each other, not to leverage the BeanFactory for creation particularly.

@rwinch
Copy link
Author

rwinch commented Feb 29, 2016

@dsyer Thanks for the response.

The sample app broken because it is passing cookies downstream from the gateway to the resource server, and it shouldn't need to do that because the authentication is via the OAuth2 token in this sample. The resource server fails when it tries to hydrate a session from redis that it doesn't need to know about. It works for me with Brixton snapshots because the gateway isn't passing the cookie downstream any more. It also works as is if you remove the redis and spring session dependencies from the resource server (they aren't needed anyway, so that's perfectly acceptable in this case).

You stop running the code that causes the issue, but that isn't the goal. The goal is to be able to authenticated to the ui using OAuth and then authenticate to the resource applications using Spring Session. If you look at the oauth-session it demonstrates the overall goal with the necessary workarounds in place.

I should point out that this is a general problem with serialization/deserialization of the BeanFactory when the GenericScope is being used due to the serializationId changing. This scenario is really just one way in which this problem is manifested.

As far as the general issue goes with GenericScope I couldn't find any problem with the serialization ID in a single application (as opposed to multiple, manifestly different application contexts). So it seems like the bean names are deterministic and the ID is a decent enough representation of the context.

This is quite interesting. I have been able to reproduce the problem with a single application as well. While the bean names can produce the same result the results are not deterministic. This is true in part because classpath scanning is not deterministic. This means the order in which the beans are resolved is not deterministic.

I created a branch, gh-93-serialization-session-scope-beans, that demonstrates the problem in an isolated test named SerializeSessionScopeBeanTests.

We could consider changing the OAuth2 library, but it would be a large enough change that we would need to wait for 3.0, I guess.

This could certainly help in the Spring Security OAuth case. However, if users are serializing the BeanFactory for other reasons, they could still have this problem.

@dsyer
Copy link
Contributor

dsyer commented Feb 29, 2016

Ah, @ComponentScan how I loathe thee. I'll look into that, and thanks for the (a bit) simpler test case.

I think we are at cross purposes though. The 2 apps that you are trying to share a session between are not ever expected to have the same serialization ID (they are different). So you don't have to go to any great lengths to trick them into breaking when you share a session. The point is that by construction they don't need to share a session, so the experiment is somewhat uninformative.

@rwinch
Copy link
Author

rwinch commented Feb 29, 2016

@dsyer I think there are two problems at hand here.

The first is that the BeanFactory instances are not consistently serializable due to the serializationId changing. This is illustrated within a single application instance and will be fixed if the BeanFactory serializationId is consistent.

The second issue is that OAuth2ClientContext is requiring the BeanFactory in the first place. Consider a single application that serializes OAuth2ClientContext. The application is updated to include one more bean name. The is then started up again and tries to deserialize the previous OAuth2ClientContext. The deserialization will now fail (if the serialization id changes based upon the names).

I think that Spring Security OAuth should serialize OAuth2ClientContext in a way that it is not impacted by the underlying BeanFactory. This means that the OAuth2ClientContext would also work across multiple applications as this sample is trying to do. I think this is worth creating an issue in Spring Security OAuth for spring-attic/spring-security-oauth#705

The point is that by construction they don't need to share a session, so the experiment is somewhat uninformative.

The applications still need to share session, it is just done by serializing/deserializing the JWT token instead. If you think about a session in a generic sense it is exchanging one set of credentials (i.e. username/password, JWT token, SAML assertion, etc) for another (session id). If a user is wanting to exchange a JWT token for a session id, then they should be allowed to do so.

PS: The sample I chose just happened to be a good starting point to illustrate that users may want to exchange a JWT token for a session id. More generally, users may want to serialize OAuth2ClientContext and have that work when they add another bean definition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants