Using Freemarker's FreemarkerServlet is giving me problems in that the HttpSessionHashModel caches the HttpSession. This is a problem because if the session is invalidated then an exception is thrown.
The problem presented itself when using Spring Security. What happens is that Spring Security creates a new HttpSession, invalidates the old one, and then copies over all the attributes upon a successful login. One of the parameters that gets copied over is the HttpSessionHashModel, which has the old HttpSession inside it. So we essentially get a session inside a session.
The code that is causing problems is this (FreemarkerServlet.createModel()).
The only way to ensure that the HttpSessionHashModel has the current session is to create a new one on every request. The only real downside is that the initializeSession() callback does not make sense because it would be called each time.
It is a standard practice to store session-specific objects as session attributes. I'd say that the practice of Spring Security, where it invalidates the session, creates a new one, and copies all attributes is an odd one and the one actually responsible for the bug.
There is an easy way to fix this though: I changed the HttpSessionHashModel.isZombie() method from:
and the code in FreeMarkerServlet#createModel() is now calling isOrphaned accordingly and creating a new HttpSessionHashModel when it returns true. This ensures that initializeSession() is not run too often.
I fixed this in the tip of the 2.3 branch - can you grab it from the SVN from and see whether it now works as you'd expect it to.
Yeah, we're lazy - we got tired of assisting people building it, or having to build it for them, so we figured we might as well make it build out-of-the-box ;-)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Using Freemarker's FreemarkerServlet is giving me problems in that the HttpSessionHashModel caches the HttpSession. This is a problem because if the session is invalidated then an exception is thrown.
The problem presented itself when using Spring Security. What happens is that Spring Security creates a new HttpSession, invalidates the old one, and then copies over all the attributes upon a successful login. One of the parameters that gets copied over is the HttpSessionHashModel, which has the old HttpSession inside it. So we essentially get a session inside a session.
The code that is causing problems is this (FreemarkerServlet.createModel()).
HttpSession session = request.getSession(false);
if(session != null) {
sessionModel = (HttpSessionHashModel) session.getAttribute(ATTR_SESSION_MODEL);
if (sessionModel == null || sessionModel.isZombie()) {
sessionModel = new HttpSessionHashModel(session, wrapper);
session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
if(!sessionModel.isZombie()) {
initializeSession(request, response);
}
}
}
The only way to ensure that the HttpSessionHashModel has the current session is to create a new one on every request. The only real downside is that the initializeSession() callback does not make sense because it would be called each time.
HttpSession session = request.getSession(false);
if(session != null) {
sessionModel = (HttpSessionHashModel) session.getAttribute(ATTR_SESSION_MODEL);
sessionModel = new HttpSessionHashModel(session, wrapper);
session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
}
Any thoughts? Its really a pretty nasty bug! For right now I overwrote the createModel() method and modified it accordingly.
It is a standard practice to store session-specific objects as session attributes. I'd say that the practice of Spring Security, where it invalidates the session, creates a new one, and copies all attributes is an odd one and the one actually responsible for the bug.
There is an easy way to fix this though: I changed the HttpSessionHashModel.isZombie() method from:
boolean isZombie()
{
return session == null && request == null;
}
to:
boolean isOrphaned(HttpSession currentSession)
{
return session != currentSession || (session == null && request == null);
}
and the code in FreeMarkerServlet#createModel() is now calling isOrphaned accordingly and creating a new HttpSessionHashModel when it returns true. This ensures that initializeSession() is not run too often.
I fixed this in the tip of the 2.3 branch - can you grab it from the SVN from and see whether it now works as you'd expect it to.
: https://freemarker.svn.sourceforge.net/svnroot/freemarker/branches/2.3/freemarker "SVN 2.3.x branch"
Or just download the freemarker.jar build from ; will be automatically generated soon.
: http://freemarker.org/builds/
Thanks! I will try it out on Monday when I get into work.
What Spring Security is trying to protect against is called a .
: http://static.springsource.org/spring-security/site/docs/2.0.x/reference/ns-config.html
Works great! Thanks!!
I also admire how easy it is to get the source and run the ant build file. Makes it very easy to work with freemarker from the source directly.
Yeah, we're lazy - we got tired of assisting people building it, or having to build it for them, so we figured we might as well make it build out-of-the-box ;-)