Web应用程序中的NTLM身份validation(java)

我在我的Web应用程序中使用以下filter来启用NTLM身份validation。

我得到了Windows浏览器身份validation提示。 它工作正常。 除了这个事实 – 我无法判断身份validation是成功还是失败! * 两种情况都没有错误。 *在每种情况下都会打印用户名(正确或其他),工作站等。

package com.test; import java.io.IOException; import java.io.PrintStream; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import jcifs.ntlmssp.Type3Message; import com.sun.xml.internal.ws.util.StringUtils; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class NTLMUserFilter implements Filter { private FilterConfig filterConfig = null; private String userDomain = null; public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String username = null; //first, get the user agent String useragent = request.getHeader("user-agent"); //if you're using IE, you can continue if ((useragent.indexOf("MSIE") > -1)){ //Always do the ntlm check (for IE POST back) try{ String auth = request.getHeader("Authorization"); if (auth == null) { response.setHeader("WWW-Authenticate", "NTLM"); response.setStatus(response.SC_UNAUTHORIZED); response.setContentLength(0) ; response.flushBuffer(); return; } if (auth.startsWith("NTLM ")) { byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5)); int off = 0, length, offset; if (msg[8] == 1) { byte z = 0; byte[] msg1 = {(byte)'N', (byte)'T', (byte)'L', (byte)'M', (byte)'S', (byte)'S', (byte)'P', z,(byte)2, z, z, z, z, z, z, z,(byte)40, z, z, z, (byte)1, (byte)130, z, z,z, (byte)2, (byte)2, (byte)2, z, z, z, z, z, z, z, z, z, z, z, z}; response.setHeader("WWW-Authenticate", "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1)); response.setStatus(response.SC_UNAUTHORIZED); response.setContentLength(0) ; response.flushBuffer(); return; } else if (msg[8] == 3) { //Did Authentication Succeed? All this is always printed. Type3Message type3 = new Type3Message(msg); System.out.println("osUser: " + type3.getUser()); System.out.println("osRemoteHost: + " + type3.getWorkstation()); System.out.println("osDomain: " + type3.getDomain()); } } }catch(Exception e){ System.out.println(e) ; } //System.out.println("Suc); } try { chain.doFilter(req, res); } catch (IOException e) { System.out.println(e); } catch (ServletException e) { System.out.println(e); } } public void destroy() { this.filterConfig = null; } } 

web.xml很简单:

  ntlmFilter  com.test.NTLMUserFilter     ntlmFilter /*  

您收到了Type 3消息,但除了打印出详细信息外,您没有对其进行任何操作。 您需要在此时validation客户端的响应,并发送200(如果已授权)或401(如果没有)。

但是,您传递的Type 1消息由静态字节组成,并且 – 虽然它会诱使客户端发回响应 – 但大多数都是无意义的。 自己实现完整的NTLM身份validation堆栈并非不可能,但是您拥有的代码根本无法工作。

您可以调查用于Java的NTLM解决方案 ,或者(假设您在Windows上)可以使用JNI调用必要的身份validation函数,如AcceptSecurityContext

正如Edward所说,只是从类型3(响应)NTLM消息中提取名称并没有说明生成它的客户端是否有权这样做。

NTLM不像Kerberos,其中有一个签名的令牌,服务可以自己validation; 你必须每次都与域控制器建立连接,询问它是否合法。 实现MSRPC连接以检查NTLM令牌真的很难。

在过去,您可以使用jcifs.smb.SmbSession在JCIFS中执行此jcifs.smb.SmbSession ,而jcifs.http.NtlmHttpFilter将为您执行此操作。 但是,这仅适用于NTLMv1,这是旧的,不安全的,并且越来越不可能用于任何事情。 (我相信上面链接的’ntlm-java’也只是NTLMv1。)

试试ntlmv2auth项目。

NTLM-over-HTTP足以让人感到痛苦,通常使用任何其他可用的身份validation方法都会更好。