简体   繁体   English

使用Java使用Active Directory进行NTLM身份验证

[英]NTLM Authentication with Active Directory using Java

I was reading this article , with the help of it I am able to find the username, domain name and hostname of the machine accessing my JSP Page, But Still I can't understand how to authenticate the user. 我正在阅读这篇文章 ,在它的帮助下,我能够找到访问我的JSP页面的机器的用户名,域名和主机名,但我仍然无法理解如何验证用户。 Because in Firefox when I am accessing my JSP page and try to enter correct Username but wrong password, it authenticates the user. 因为在我访问JSP页面并尝试输入正确的用户名但密码错误的Firefox中,它会对用户进行身份验证。

So the prime concern is how can I authenticate the user with NTLM Protocol, ie once I have the username and password, I can make a LDAP request to authenticate the user, but here only Username of the person is known to server. 因此,主要关注的是如何使用NTLM协议对用户进行身份验证,即,一旦我拥有用户名和密码,我就可以发出LDAP请求来验证用户,但是这里只有服务器知道此人的用户名。

<%

String auth = request.getHeader("Authorization");
/*
 * Client to Server - Get Page.
 */
if (auth == null) {

    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    response.setHeader("WWW-Authenticate", "NTLM");
    return;
}
/*
 * Client to Server 
 GET ...
 Authorization: NTLM <base64-encoded type-1-message>

Type 1 Message - 
        0       1       2       3
        +-------+-------+-------+-------+
    0:  |  'N'  |  'T'  |  'L'  |  'M'  |
        +-------+-------+-------+-------+
    4:  |  'S'  |  'S'  |  'P'  |   0   |
        +-------+-------+-------+-------+
    8:  |   1   |   0   |   0   |   0   |
        +-------+-------+-------+-------+
    12:  | 0x03  | 0xb2  |   0   |   0   |
        +-------+-------+-------+-------+
    16:  | domain length | domain length |
        +-------+-------+-------+-------+
    20:  | domain offset |   0   |   0   |
        +-------+-------+-------+-------+
    24:  |  host length  |  host length  |
        +-------+-------+-------+-------+
    28:  |  host offset  |   0   |   0   |
        +-------+-------+-------+-------+
    32:  |  host string                  |
        +                               +
        .                               .
        .                               .
        +             +-----------------+
        |             | domain string   |
        +-------------+                 +
        .                               .
        .                               .
        +-------+-------+-------+-------+
 */
if (auth.startsWith("NTLM ")) {



    byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth
            .substring(5));
    int off = 0, length, offset;
    String s;
    s = new String(msg, 0, msg.length);

    if (msg[8] == 1) {

        off = 18;

        byte z = 0;
        /*
                    0       1       2       3
         +-------+-------+-------+-------+
     0:  |  'N'  |  'T'  |  'L'  |  'M'  |
         +-------+-------+-------+-------+
     4:  |  'S'  |  'S'  |  'P'  |   0   |
         +-------+-------+-------+-------+
     8:  |   2   |   0   |   0   |   0   |
         +-------+-------+-------+-------+
    12:  |   0   |   0   |   0   |   0   |
         +-------+-------+-------+-------+
    16:  |  message len  |   0   |   0   |
         +-------+-------+-------+-------+
    20:  | 0x01  | 0x82  |   0   |   0   |
         +-------+-------+-------+-------+
    24:  |                               |
         +          server nonce         |
    28:  |                               |
         +-------+-------+-------+-------+
    32:  |   0   |   0   |   0   |   0   |
         +-------+-------+-------+-------+
    36:  |   0   |   0   |   0   |   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, 
                        (byte) 1, (byte) 9, (byte) 0, (byte) 9, 
                        (byte) 1, (byte) 9, (byte) 8, (byte) 9,  
                        z, z, z, z, 
                        z, z, z, z };
        // 
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setHeader("WWW-Authenticate", "NTLM "
                + new sun.misc.BASE64Encoder().encodeBuffer(msg1)
                        .trim());
        return;
    } 
    /*
     * Client sending type 3 message.

        0       1       2       3
        +-------+-------+-------+-------+
    0:  |  'N'  |  'T'  |  'L'  |  'M'  |
        +-------+-------+-------+-------+
    4:  |  'S'  |  'S'  |  'P'  |   0   |
        +-------+-------+-------+-------+
    8:  |   3   |   0   |   0   |   0   |
        +-------+-------+-------+-------+
   12:  |  LM-resp len  |  LM-Resp len  |
        +-------+-------+-------+-------+
   16:  |  LM-resp off  |   0   |   0   |
        +-------+-------+-------+-------+
   20:  |  NT-resp len  |  NT-Resp len  |
        +-------+-------+-------+-------+
   24:  |  NT-resp off  |   0   |   0   |
        +-------+-------+-------+-------+
   28:  | domain length | domain length |
        +-------+-------+-------+-------+
   32:  | domain offset |   0   |   0   |
        +-------+-------+-------+-------+
   36:  |  user length  |  user length  |
        +-------+-------+-------+-------+
   40:  |  user offset  |   0   |   0   |
        +-------+-------+-------+-------+
   44:  |  host length  |  host length  |
        +-------+-------+-------+-------+
   48:  |  host offset  |   0   |   0   |
        +-------+-------+-------+-------+
   52:  |   0   |   0   |   0   |   0   |
        +-------+-------+-------+-------+
   56:  |  message len  |   0   |   0   |
        +-------+-------+-------+-------+
   60:  | 0x01  | 0x82  |   0   |   0   |
        +-------+-------+-------+-------+
   64:  | domain string                 |
        +                               +
        .                               .
        .                               .
        +           +-------------------+
        |           | user string       |
        +-----------+                   +
        .                               .
        .                               .
        +                 +-------------+
        |                 | host string |
        +-----------------+             +
        .                               .
        .                               .
        +   +---------------------------+
        |   | LanManager-response       |
        +---+                           +
        .                               .
        .                               .
        +            +------------------+
        |            | NT-response      |
        +------------+                  +
        .                               .
        .                               .
        +-------+-------+-------+-------+
     */
    else if (msg[8] == 3) {

        off = 30;
        length = msg[off + 17] * 256 + msg[off + 16];
        offset = msg[off + 19] * 256 + msg[off + 18];

        s = new String(msg, offset, length);

        System.out.println("Host String - " + s + " ");
    } else{

        return;
    }
    /*
     * Reading domain information
     */
    length = msg[off + 1] * 256 + msg[off];
    offset = msg[off + 3] * 256 + msg[off + 2];     
    s = new String(msg, offset, length);
    System.out.println("Domain Name - " + s +  " ");

    /*
     * Reading User Name information.
     */
    length = msg[off + 9] * 256 + msg[off + 8];
    offset = msg[off + 11] * 256 + msg[off + 10];

    s = new String(msg, offset, length);
    System.out.println("User Name - " + s + " ");

In the following thread they put the Tomcat behind an Apache Server and use an Apache Module to perform the NTLM authentication. 在下面的线程中,他们将Tomcat放在Apache服务器后面,并使用Apache模块执行NTLM身份验证。

Spring 3 and NTLM authentication Spring 3和NTLM身份验证

NTLM authentication does not use a password, it uses a challenge-response protocol which requires a few server roundtrips. NTLM身份验证不使用密码,它使用挑战 - 响应协议,需要一些服务器往返。

In the second GET request, you respond with a server 'nonce' which is the authentication challenge received from the domain controller. 在第二个GET请求中,您使用服务器“nonce”进行响应,这是从域控制器收到的身份验证质询。 On the third GET, you get the authentication response which you can validate with the challenge via the domain controller. 在第三个GET上,您将获得身份验证响应,您可以通过域控制器通过质询验证。

In your code, you use a hard-coded challenge (0x19091989), and completely ignore the response. 在您的代码中,您使用硬编码质询(0x19091989),并完全忽略响应。

JCIFS has an implementation that actually finds a domain controller to handle the challenge and response in http://code.google.com/p/jcifs-fork/source/browse/trunk/jcifs/src/jcifs/http/NtlmHttpFilter.java . http://code.google.com/p/jcifs-fork/source/browse/trunk/jcifs/src/jcifs/http/NtlmHttpFilter.java中 ,JCIFS实际上找到了一个实现域控制器来处理挑战和响应的实现。 You could reverse engineer this, or use the filter 'an sich' as described in http://jcifs.samba.org/src/docs/ntlmhttpauth.html . 您可以对此进行反向工程,或者使用http://jcifs.samba.org/src/docs/ntlmhttpauth.html中描述的过滤器“an sich”。 AFAIK this only works on a Windows server, but I could be mistaken. AFAIK这只适用于Windows服务器,但我可能会弄错。

您所要做的就是按照这篇文章使Firefox能够使用像IE和Chrome那样的NTLM!

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

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