javavaadinsession-variablesvaadin7shiro

Session replication with VaadinSession not working


We have a web application that is using Spring Boot (1.5) with Vaadin (7.7), and is using Apache Shiro (1.4.0) for security.

The application is configured to use DefaultWebSessionManager to let Shiro handle the session management instead of the servlet container.

We are using the official Vaadin Spring integration (1.2.0), and after some configuration it all works as intended. The VaadinSession contains a wrapped ShiroHttpSession internally.

We want to achieve session replication, by configuring Shiro to use a SessionDAO that is backed by an external Cache, which means the sessions get (de)serialized.

As soon as we start using this SessionDAO, Vaadin will crash and stop working. When replace the external cache by an in memory Map for the sake of debugging, it works again.

It seems this is caused by the SpringVaadinServlet, as it stores the VaadinSession as a session attribute. VaadinSession is Serializable and the Javadoc shows:

Everything inside a VaadinSession should be serializable to ensure compatibility with schemes using serialization for persisting the session data.

Inside the VaadinSession are some fields that are not Serializable, for example a Lock and the wrapped http session inside is also marked as transient.

Because of this, the session that Vaadin uses will be broken as soon as it is distributed, resulting in a lot of crashes.

So it turns out the VaadinSession is not actually usable in session replication? Why is this and how can we work around this?

Note: we also have a version of the application that is using Vaadin 8, and here the same thing happens. It seems that the issue is caused by the Vaadin Spring integration.


Solution

  • Inside the VaadinSession are some fields that are not Serializable, for example a Lock and the wrapped http session inside is also marked as transient.

    The wrapped http session is not part of Vaadin session, it is the the http session. Thus it is transient. The same can be said about Lock, whose instance is stored in the http session.

    In order to implement session serialization correctly, you need to hook into serialization events and update the transients when session is being deserialized. VaadinSession should be loaded with VaadinService#loadSession, which calls VaadinSession#refreshTransients.

    Everything inside a VaadinSession should be serializable to ensure compatibility with schemes using serialization for persisting the session data.

    This statement does not imply that you can serialize your application out of the box. It just means, that in case your application is serializable as well, with careful engineering you can serialize the whole thing.

    For example Vaadin is not updating the session attribute in each possible occasion for performance reasons. There is method VaadinService#storeSession for that. So you need to either override right method or setup request filter. E.g. you could do this at VaadinService#endRequest.

    Note, you need to use sticky sessions in order to get this to work with moderate amount of effort. If your session is de-serialized in different machine, the re-entrant lock instances wont be valid. If you would like to be able to de-serialize the session in different machine, it would require that your infrastructure can offer distributed lock that you can use instead of re-entrant Lock of Java and override Vaadin's getSessionLock and setSessionLock methods to use that.

    Valuable sources of further info:

    Generic notes from Vaadin's CTO

    https://vaadin.com/blog/session-replication-in-the-world-of-vaadin

    Testimonial from developer who did it with one stack

    https://vaadin.com/learn/tutorials/hazelcast

    Thoughts from another senior developer

    https://mvysny.github.io/vaadin-14-session-replication/