简体   繁体   English

NTLM身份验证Java

[英]NTLM authentication java

I'm programming NTLM authentication in Java EE. 我正在Java EE中编程NTLM身份验证。 If "windows integrated authentication" is enabled in the browser like Internet Explorer so everything works good (the browser send user's name to the server ). 如果在Internet Explorer之类的浏览器中启用了“ Windows集成身份验证”,则一切正常(浏览器将用户名发送到服务器)。 But if "windows integrated authentication" is disabled like Mozilla firefox, the browser display an at authentication form where user have to enter his login and password. 但是,如果像Mozilla firefox这样的“ Windows集成身份验证”被禁用,浏览器将显示一个at身份验证表单,用户必须在其中输入其登录名和密码。 My problem is: In the second case when the user enter his login and password, i can get login from the server side, but i can't get password. 我的问题是:在第二种情况下,当用户输入他的登录名和密码时,我可以从服务器端登录,但是我无法获得密码。 I have to get a password otherwise every user only just have to know the username of another user to authenticate in his place. 我必须输入密码,否则每个用户只需要知道另一个用户的用户名就可以代替他进行身份验证。

My code below: 我的代码如下:

 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    /**
     * NTLM
     */
    String auth = request.getHeader("Authorization");
    //No NTLM authentification
    if (auth == null) {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setHeader("WWW-Authenticate", "NTLM");
        return;
    }
    //check what client sent
    if (auth.startsWith("NTLM")) {
        byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
        int off = 0, length, offset;

        if (msg[8] == 1) {
            off = 18;
            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};

            // send ntlm type2 msg
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setHeader("WWW-Authenticate", "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1).trim());
            return;
        } //receive ntlm type 3 msg
        else if (msg[8] == 3) {
            off = 30;

            //username
            length = msg[off + 9] * 256 + msg[off + 8];
            offset = msg[off + 11] * 256 + msg[off + 10];
            username = new String(msg, offset, length);

            //remoteHost
            length = msg[off + 17] * 256 + msg[off + 16];
            offset = msg[off + 19] * 256 + msg[off + 18];
            remoteHost = new String(msg, offset, length);

            //domain
            length = msg[off + 1] * 256 + msg[off];
            offset = msg[off + 3] * 256 + msg[off + 2];
            domain = new String(msg, offset, length);
        } else {
            return;
        }

    }
    /**
     * END NTLM
     */

    request.setAttribute("username", username);
    request.setAttribute("remoteHost", remoteHost);
    request.setAttribute("domain", domain);
    request.setAttribute("ipAdress", request.getRemoteAddr());
    request.setAttribute("remotePort", request.getRemotePort());
    request.setAttribute("protocol", request.getProtocol());
    this.getServletContext().getRequestDispatcher("/WEB-INF/index.jsp").forward(request, response);

You need to send the following HTTP header in order to get the password from client: 您需要发送以下HTTP标头,以从客户端获取密码:

WWW-Authenticate: Basic realm="insert realm"

The problem is how to decide whether to request NTLM or Basic authentication. 问题是如何决定是否请求NTLM或基本身份验证。 One approach is to first ask for NTLM, in case the response cannot be verified, then ask for Basic (and therefore get the password). 一种方法是,如果无法验证响应,则首先要求NTLM,然后要求“基本”(并因此获得密码)。 You could also detect on server side which browser your client uses or from which IP is he accessing and decide whether to use NTLM or Basic based on this data. 您还可以在服务器端检测您的客户端使用哪个浏览器或他从哪个IP访问,并根据此数据决定使用NTLM还是Basic。

Some browsers can also handle getting both NTLM and Basic headers at the same time and decide on which one to use based on their capabilities: 某些浏览器还可以同时获取NTLM和Basic标头,并根据其功能决定使用哪个标头:

WWW-Authenticate: NTLM
WWW-Authenticate: Basic realm="insert realm"
String auth = request.getHeader("Authorization");
//No NTLM authentification
if (auth == null) {
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    response.setHeader("WWW-Authenticate", "NTLM");
    return;
}
  //when the integrated authentication is disabled
 //basic authentication
 if((auth !=null)&&(!auth.startsWith("NTLM")))
{
        {
        StringTokenizer st = new StringTokenizer(auth);
        if(st.hasMoreTokens()){

            String basic = st.nextToken();
            if (basic.equalsIgnoreCase("Basic")) {
            try{
              String credentials = new String(Base64.decode(st.nextToken()));  
                int p = credentials.indexOf(":");
                if (p != -1) {
                     username = credentials.substring(0, p).trim();
                     password = credentials.substring(p + 1).trim();
                } 
            }catch(Exception e){


            }
        }
        } 
    }

    }

//check what client sent
if (auth.startsWith("NTLM")) {
    byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
    int off = 0, length, offset;

    if (msg[8] == 1) {
        off = 18;
        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};

        // send ntlm type2 msg
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setHeader("WWW-Authenticate", "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1).trim());
        return;
    } //receive ntlm type 3 msg
    else if (msg[8] == 3) {
        off = 30;

        //username
        length = msg[off + 9] * 256 + msg[off + 8];
        offset = msg[off + 11] * 256 + msg[off + 10];
        username = new String(msg, offset, length);

        //remoteHost
        length = msg[off + 17] * 256 + msg[off + 16];
        offset = msg[off + 19] * 256 + msg[off + 18];
        remoteHost = new String(msg, offset, length);

        //domain
        length = msg[off + 1] * 256 + msg[off];
        offset = msg[off + 3] * 256 + msg[off + 2];
        domain = new String(msg, offset, length);
    } else {
        return;
    }

}

Why are you wasting your time with proprietary stuff? 你为什么要浪费时间用专有的东西? Use Kerberos . 使用Kerberos

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

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