Single Sign-On: Servlet Negotiate Security Filter (Kerberos + NTLM) w/ Waffle

Back | tomcat, waffle, security, java, active directory | 5/25/2010 |

Jamais deux sans trois.

waffleIn a previous post I showed how to use the Waffle Tomcat Authenticator to implement single-sign-on with Tomcat. That works very well and utilizes the concept of Tomcat realms to protect various resources. Turns out, there’re disadvantages to this approach. These are quite well explained in the Tomcat Security Filter project. It all boils down to not requiring a realm, so lets see how to use the Waffle NegotiateSecurityFilter with Tomcat (you should be able to use it with other implementations, including Jetty).

Download

Download Waffle 1.3. The zip contains Waffle.chm that has the latest version of this tutorial.

Configure Tomcat

Copy Files

Copy waffle-jna.jar, jna.jar and platform.jar to Tomcat's lib directory. You can package these files with your application, but this is easier for the demonstration.

Security Filter

Add the security filter to WEB-INF\web.xml.

  1. <filter>
  2.   <filter-name>SecurityFilter</filter-name>
  3.   <filter-class>waffle.servlet.NegotiateSecurityFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6.   <filter-name>SecurityFilter</filter-name>
  7.   <url-pattern>/*</url-pattern>
  8. </filter-mapping>

That’s it.

Demo Application

A demo application can be found in the Waffle distribution in the Samples\Tomcat\waffle-filter directory. Copy the entire directory into Tomcat's webapps directory and navigate to http://localhost:8080/waffle-filter/.

Retrieving User Principal

If you’re familiar with Tomcat you’ll be surprised that <%= request.getUserPrincipal().getName() %> works in a JSP page with this filter in place and no realm configuration. Theoretically Tomcat says you cannot assign a Principal to the request in a filter. The guys at the Tomcat Security Filter Project found a very simple solution – wrap the request up and pass the wrapper into the next filter in the chain. We use the same technique as you can see in NegotiateSecurityFilter.java and NegotiateRequestWrapper.java.

  1. WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity, null, _principalFormat, _roleFormat);
  2. subject.getPrincipals().add(windowsPrincipal);
  3. session.setAttribute("javax.security.auth.subject", subject);
  4. NegotiateRequestWrapper requestWrapper = new NegotiateRequestWrapper(request, windowsPrincipal);
  5. chain.doFilter(requestWrapper, response);

Links