Closed Selindek closed 9 years ago
Hey @Selindek, after looking into this I agree with your original assessment. I had hoped to be able to preserve backwards compatibility with previous versions by only setting the manager after all fields on the session have been set (setManager is just a normal setter with no additional side effects of registering the session). Unfortunately when going down that avenue I discovered that we are not setting the accessed time correctly. We only set the creation time of the session which initializes the access time to the same value, we store the last accessed time in the database but do nothing with it. This too is a pretty serious bug as sessions can be reaped before they are truly expired. The access time doesn't have an exposed setter, calls to access() just set the last accessed time to the current time. It looks like the only option to set the last accessed time would be to subclass StandardSession to gain direct access to those fields or use the serialization/deserialization methods you pointed out in your pull request. I prefer your approach as it's less susceptible to breaking changes in StandardSession across different versions of Tomcat but would like to discuss the options with @fulghum before proceeding.
We have decided to accept this pull request with a few changes to allow existing customers to migrate without rebuilding the session table. Can you confirm you are submitting the code to Amazon under the Apache 2.0 license?
Yes, I confirm.
Thanks for your contribution @Selindek!
Here is the full story behind this version:
I tried to explore the issue discussed here: https://github.com/aws/aws-dynamodb-session-tomcat/issues/18 I took the trouble and examined how the session handling works in Tomcat and also analysed the whole package line by line. It turned out that this is not a simple bug but a very serious logic error in the algorithm.
Let's see the issues step by step:
manager.add(session);
The session is added to the manager inside the load method. Let's see what happens here:
Let's assume a user has made some changes in his session but the session is not stored yet, because it's only stored after a 30 seconds idle interval. Then Tomcat's own sessionReaper starts working. It goes through all the sessions in the store, so it also loads this user's session too using the load method mentioned above. Of course the session is not expired so it won't delete it, but during the load method the freshly loaded - but out-of-date session will be registered to the manager. Because it has the same sessionId as the already existing - and updated - session (of course) it will simply override the actual session in the manager! And that's exactly what we experienced and what was described in the mentioned issue above. The session has switched back to an earlier state!
Session session = getManager().createSession(id);
Basically when you provide an id and a manager object to a session, it will be instantly registered to the manager. There is only one exception: If we use the StandardSession's own deserialization method. Because it HAS an own and very well implemented serialization and deserialization method in it!
So, why do we want to serialize and deserialize the session objects by our own way, when we could use the original, well tested and managed methods? The JSBCSessionStore and FileSessionStore implemetations also use these methods and they work perfectly.
So I made the following changes:
I also changed the major version number, because the new manager is NOT compatible with the previous versions. The sessions are stored in a different format now in the DB.