Thursday, January 3, 2013

Non-blocking server push with Atmosphere, Wicket and Spring Security

Previous blog post described how to make Wicket, Spring Security and Atmosphere work together. However, it covered only one part of the story - the blocking transport technique (e.g. long polling). We tried to enable non-blocking protocol and run instantly into several problems emerging mainly from the necessity to use Spring Security filter chain along with Wicket filter and Atmosphere servlet:

The problems were:
  • Spring Security authentication did not work with NIO (non-blocking) connector on Tomcat. My guess is that the filter was not applied.
  • AtmosphereServlet is configurable via atmosphere.xml where you define AtmosphereHandlers. The problem is that you cannot define multiple filters similarly to web.xml.
  • AtmosphereFramework has a regexp which is used to map request path to AtmosphereHandlers mapped to /*. It does not contain underscore which is part of default form-login processing-url of SpringSecurity (j_spring_security_check).
Let's see how we dealt with these problems.

First of all, install the newest version of Tomcat 7 as non-blocking support was developed rather recently and it may not work properly with older versions. We used Tomcat 7.0.34.

Modify the HTTP connector in server.xml

Atmosphere will initiate non-blocking transport only if you include some context.xml in META-INF or exclude atmosphere-compat-tomcat7 from your classpath. We encountered a problem with SpringSecurity SessionFixationProtectionStrategy as request.getSession(true) did not return new session but this was fixed by using newer version of Atmosphere runtime. Our respective pom.xml part looks like this:
Then we need to define the two filters inside AtmosphereHandler defined in atmosphere.xml. We decided to do it programmatically. Here is our atmosphere.xml

And the CustomAtmosphereHandler looks like this:

CustomAtmosphereHandler was inspired by Atmosphere ReflectorServletProcessor. It creates both SpringSecurity and Wicket filters programmatically. In case of Wicket it loads the application in the same manner as the org.apache.wicket.spring.SpringWebApplicationFactory.
Custom FilterConfig gives us control over init parameters. Interestingly, Wicket-Atmosphere integration uses in the mapping filter mapping path from InitParam instead of the filter path set on the WicketFilter. Thus we need to add the init param FILTER_MAPPING_PARAM. We decided to do it this way because otherwise we will have filter configuration scattered over CustomAtmosphereHandler and web.xml.

Our web.xml is then fairly simple:

Now one last finishing touch:) We need to alter default SpringSecurity path so that it is mapped to our CustomAtmosphereHandler so modify the form-login line in your spring-security.xml:

Here is a link to a sample application: