Closed BenDol closed 5 years ago
The corruption of the session could be due to some debug breakpoints I had where I stopped the application while development (before the cookie serializer had time to write the cookie?). But I am somewhat suspicious given the fact that the cookie value seems to be in a different format to springs.
EDIT: It happened again out of the blue, this time it was a fresh database, seems that the session ID is being set somewhere else perhaps?
I suspect since I have added the property server.servlet.session.cookie.name
it is trying to push the JSESSIONID into this session cookie as well as my actual session? I'm not really sure how that all works if it is the case. I removed that property and haven't had the issue since, I'll keep an eye out for it though.
EDIT: I think the issue is similar to this: https://github.com/spring-projects/spring-session/issues/607
Thanks for the report @BenDol. Could you provide a minimal sample app that we could use to reproduce this?
cookie = {Cookie@13809}
name = "BSESSION"
value = "2342674501D2E98A7A5AFEE4073C5A16"
comment = null
domain = null
maxAge = -1
path = null
secure = false
version = 0
isHttpOnly = false
sessionId = "�~6�9�P��
Looking at this, it doesn't seem this is a cookie generated by Spring Session. What then happens is that DefaultCookieSerializer
attempts to Base64 decode cookie value and gets garbled output.
@vpavic I'll put together a sample asap and you are correct, the session is being created by tomcat I think. When I remove the server.servlet.session.cookie.name
property from my properties file the issue goes away and the JSESSIONID cookie all of a sudden appears when I run the application. So it seems like it's trying to push the JSESSIONID to the renamed session cookie name and in turn causing this error.
Closing due to lack of feedback. Please comment back if you can provide more details and we can re-open the issue.
That being said, I believe the problem here lies outside of Spring Session, and is ordering related similarly like with #607 that you linked.
Reopening instead of duplicate issue #1257 - please try to provide a minimal sample app that we could use to reproduce this. I suspect there is some request that isn't mapped on to our SessionRepositoryFilter
so containers session management kicks in. If that's the case, this should be a configuration error but we need to be sure.
I will try set up a sample environment when I have more time, it would mean reversing an app that requires oauth2 servers etc.
In the mean time I've found scopedTarget.oauth2ClientContext
is the bean that is invoked in the AbstractBeanFactory#getBean
which calls RequestFacade#getSession
upon creation. Seems that it goes to the ManagerBase#createSession
rather than to the Spring managed session factory?
setId:349, StandardSession (org.apache.catalina.session)
createSession:665, ManagerBase (org.apache.catalina.session)
doGetSession:3043, Request (org.apache.catalina.connector)
getSession:2437, Request (org.apache.catalina.connector)
getSession:896, RequestFacade (org.apache.catalina.connector)
getSession:116, ServletRequestAttributes (org.springframework.web.context.request)
obtainSession:138, ServletRequestAttributes (org.springframework.web.context.request)
getSessionMutex:264, ServletRequestAttributes (org.springframework.web.context.request)
get:55, SessionScope (org.springframework.web.context.request)
doGetBean:350, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:199, AbstractBeanFactory (org.springframework.beans.factory.support)
getTarget:35, SimpleBeanTargetSource (org.springframework.aop.target)
invoke:193, JdkDynamicAopProxy (org.springframework.aop.framework)
getAccessToken:-1, $Proxy130 (com.sun.proxy)
getAccessToken:169, OAuth2RestTemplate (org.springframework.security.oauth2.client)
attemptAuthentication:105, OAuth2ClientAuthenticationProcessingFilter (org.springframework.security.oauth2.client.filter)
doFilter:212, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)
...
Closing due to lack of feedback. Please comment back if you can provide more details and we can re-open the issue.
@vpavic We encountered this issue as well. For us it manifested when we were migrating from using the canonical servlet session management to spring-session management.
This is related in a way to a previous issue reported around migrating to spring boot 2.0.0.RELEASE, however is distinct since there is no migration, just going from HttpSessions to spring sessions.
Any session cookies that were in browser pre-migration resulted in a corrupt state requiring users to clear their browser in order to properly interact with our services. This was hard to replicate and I needed to mimic our production environment where we have a resource server (using spring sessions) redirecting a user to an authorization server (also using spring sessions) and then redirecting back, where both servers were migrated simultaneously to the new setup.
The root cause of this appears to be a bad interplay between how tomcat generates the session ids, and how the DefaultCookieSerializer
behaves OOTB. Tomcat appears to use org.apache.catalina.util.StandardSessionIdGenerator
for generating session Id's if no other mechanism is provided. This creates a random string which is padded in order to meet the length requirements for the sessionId. The string that it produces is naturally not a base64 string, nor is it safe to be treated as a base64 string.
Unfortunately, when you migrate to the spring-session library, the DefaultCookieSerializer
is configured OOTB to treat session Ids as b64 strings (see here), decoding them prior to passing them back to the SessionRepository.
In certain circumstances, the session padded session id generated from the StandardSessionIdGenerator
when decoded as a b64
string includes \0x0
characters (byte code 0). Java does not care about this and happily converts the value to a string. Unfortunately, if you are using the Jdbc
session store (that is all that I have tested this with on postgres), the database you are interacting may only allow a certain range of values, of which \0x0
is not one of them. This leads to a DataIntegrityViolationException
which is also reported above. You can see the jshell snippet below demonstrating this:
jshell> var JSESSIONID="DE1F28DE6708BCE479BCB136DB9E9CAA";
jshell> Base64.getDecoder().decode(JSESSIONID);
$8 ==> byte[24] { 12, 77, 69, -37, -64, -60, -21, -67, 60, 4, 33, 56, -17, -48, 66, 7, 93, -6, 12, 31, 68, -12, 32, 0 }
// notice the last byte is 0... Remove the extra `A` at the end and you get:
jshell> var JSESSIONID ==> "DE1F28DE6708BCE479BCB136DB9E9CA"
jshell> Base64.getDecoder().decode(JSESSIONID)
$10 ==> byte[23] { 12, 77, 69, -37, -64, -60, -21, -67, 60, 4, 33, 56, -17, -48, 66, 7, 93, -6, 12, 31, 68, -12, 32 }
All you need to do is disable the base64 session encoding in the DefaultCookieSerializer
. You can either extend the class (however then you are responsible for configuring it yourself), or you can use the Customizer
object as shown below:
@Bean
public DefaultCookieSerializerCustomizer customizeCookieSerializer(){
return cookieSerializer -> {
cookieSerializer.setUseBase64Encoding(false);
};
}
When migrating from using servlet managed HttpSession
to SpringSessions
make sure you disable base64 encoding for your cookies, or else pre-existing cookies will result in a 500
error for end users
I am using the standard Spring Session set up and occasionally the
httpSessionIdResolver
is returning some form of corrupted session ID. Is there a way to determine if it is corrupted and avoid this? Or perhaps I have a bad configuration that is causing this to happen occasionally?From my debugging the
DefaultCookieSerializer
is returning:�~6�9�P��
The exception I receive:
I'll continue debugging and update if I make any progress, but any help is appreciated.