简体   繁体   English

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

[英]NTLM Authentication in a Web Application (java)

I am using following filter to enable NTLM Authentication, in my web-application. 我正在使用以下过滤器在我的Web应用程序中启用NTLM身份验证。

I get the windows browser authentication prompt. 我得到Windows浏览器身份验证提示。 It is working fine. 一切正常。 Except for the fact that - I am unable to tell if Authentication Succeeded or Failed !!! 除了以下事实外- 我无法确定身份验证是成功还是失败! * There are no errors in either case. * 两种情况均无错误。 * In every case username(correct or otherwise), workstation etc. is printed. *在每种情况下都将打印用户名(正确或相反),工作站等。

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;
   }
}

The web.xml is simple: web.xml很简单:

<filter>
    <filter-name>ntlmFilter</filter-name>
    <filter-class>
        com.test.NTLMUserFilter
    </filter-class>
</filter>

<!-- Filter mapping configuration   -->

<filter-mapping>
    <filter-name>ntlmFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>   

As Edward said, just extracting a name from a type 3 (response) NTLM message doesn't say anything about whether the client who generated it was entitled to do so. 正如爱德华所说,仅从类型3(响应)NTLM消息中提取名称并不会说明生成该消息的客户端是否有权这样做。

NTLM is not like Kerberos, where there's a signed token that a service can validate on its own; NTLM不像Kerberos,它有一个签名的令牌,服务可以自行验证。 you have to make a connection to the domain controller every time to ask it whether the token is legit. 您必须每次都与域控制器建立连接,以询问该令牌是否合法。 Implementing an MSRPC connection to check an NTLM token is really hard work. 实现MSRPC连接以检查NTLM令牌确实是一项艰巨的工作。

In the old days you could do this in JCIFS using a jcifs.smb.SmbSession , and jcifs.http.NtlmHttpFilter would do just that for you. 过去,您可以在JCIFS中使用jcifs.smb.SmbSession进行此jcifs.smb.SmbSession ,而jcifs.http.NtlmHttpFilter会为您完成此操作。 However, this only works for NTLMv1, which is old, insecure, and increasingly unlikely to be used for anything. 但是,这仅适用于旧的,不安全的NTLMv1,并且越来越不可能用于任何事物。 (I believe 'ntlm-java' linked above is also NTLMv1-only.) (我相信上面链接的“ ntlm-java”也仅适用于NTLMv1。)

Try the ntlmv2auth project. 尝试ntlmv2auth项目。

NTLM-over-HTTP is enough of a pain in the arse that it's usually better to use any other method of authentication available to you. HTTP上的NTLM-over-HTTP足以使您痛苦不已,通常最好使用可用的其他任何身份验证方法。

You're receiving the Type 3 message, but you're not doing anything with it except printing out the details. 您收到的是Type 3消息,但是除了打印出详细信息之外,您什么都没做。 You need to validate the client's response at this point and either send a 200 (if authorized) or a 401 (if not.) 此时,您需要验证客户的响应,并发送200(如果已授权)或401(如果未授权)。

However the Type 1 message you delivered is made up of static bytes and - while it will induce a client to send back a response - is mostly meaningless. 但是,您传递的Type 1消息是由静态字节组成的,尽管它会诱使客户端发送回响应,但大多数情况下是毫无意义的。 It's not impossible to implement a complete NTLM authentication stack yourself, but the code you have will simply not work. 自己实现一个完整的NTLM身份验证堆栈不是不可能的,但是您拥有的代码将根本无法工作。

You could investigate an NTLM Solution for Java , or (assuming you're on Windows) you could call the necessary authentication functions like AcceptSecurityContext with JNI. 您可以研究JavaNTLM解决方案 ,或者(假设您使用的是Windows)可以使用JNI调用必要的身份验证功能,例如AcceptSecurityContext

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM