We are using NTLM Windows Authentication for a Single Sign On (SSO) project.
The Spring security Filter <a href="
http://static.springframework.org/spring-security/site/apidocs/org/springframework/security/ui/ntlm/NtlmProcessingFilter.html">NtlmProcessingFilter</a> for most of the time is absolutely fine.
However the are atleast two scenarios where this fails.
1) When the session is timed out and a form.submit() request is made.
Under this situation a windows logon box is presented. For a SSO application using NTLM this is not desirable.
2) If the page makes heavy use of dwr/javascript.
In this case the page makes repeated NTLM authentication requests and stack traces are observed with the message 'This is not a Type 3 Message'.
There is a solution described in the <a href="
http://jcifs.samba.org/src/docs/ntlmhttpauth.html#proto">jcifs documentation</a>. Search for <span style="font-weight: bold;">registry key</span>. This solution works but is not suitable for many clients who would not give access to change registry settings on all their client PCs.
The fix described here applies to <a href="
http://static.springsource.org/spring-security/site/index.html">Spring-Security</a> 2.0.4
Here is my suggested Spring solution to org.springframework.security.ui.ntlm.NtlmProcessingFilter:
As an addition the filter would be improved if the access on the utility methods were changed from private allowing the class to be extended more easily.
protected void doFilterHttp(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain chain)
throws IOException, ServletException {
final HttpSession session = request.getSession();
Integer ntlmState = (Integer) session.getAttribute(STATE_ATTR);
final String authMessage = request.getHeader("Authorization");
// Check the special IE POST request with Authorization header containing
// type-1 message (see method javadoc)
if (this.reAuthOnIEPost(request)) {
if ((authMessage != null) && (authMessage.startsWith("NTLM "))) {
logger.debug("POST Request with NTLM Authorization detected.");
// decode the NTLM response from the client
byte[] src = Base64.decode(authMessage.substring(5));
// see if a type 1 message was sent by the client
if (src[8] == 1) {
logger
.debug("NTLM Authorization header contains type-1 message. Sending fake response just to pass this stage...");
Type1Message type1 = new Type1Message(src);
// respond with a type 2 message, where the challenge is null since we
// don't
// care about the server response (type-3 message) since we're already
// authenticated
// (This is just a by-pass - see method javadoc)
Type2Message type2 = new Type2Message(type1, new byte[8], null);
String msg = Base64.encode(type2.toByteArray());
response.setHeader("WWW-Authenticate", "NTLM " + msg);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentLength(0);
response.flushBuffer();
}
}
} else {
..... existing filter code
}
chain.doFilter(request, response);
}