3

我正在阅读这篇文章,在它的帮助下,我能够找到访问我的 JSP 页面的机器的用户名、域名和主机名,但我仍然不明白如何验证用户身份。因为在 Firefox 中,当我访问我的 JSP 页面并尝试输入正确的用户名但密码错误时,它会对用户进行身份验证。

所以主要关心的是如何使用 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 + " ");
4

3 回答 3

2

NTLM 身份验证不使用密码,它使用需要几次服务器往返的质询-响应协议。

在第二个 GET 请求中,您使用服务器“nonce”进行响应,这是从域控制器收到的身份验证质询。在第三个 GET 中,您将获得身份验证响应,您可以通过域控制器使用质询进行验证。

在您的代码中,您使用硬编码质询 (0x19091989),并完全忽略响应。

JCIFS 有一个实现,它实际上在http://code.google.com/p/jcifs-fork/source/browse/trunk/jcifs/src/jcifs/http/NtlmHttpFilter.java中找到一个域控制器来处理挑战和响应. 您可以对此进行反向工程,或使用http://jcifs.samba.org/src/docs/ntlmhttpauth.html中所述的过滤器“an sich” 。AFAIK 这仅适用于 Windows 服务器,但我可能弄错了。

于 2013-10-02T09:07:13.627 回答
1

在下面的线程中,他们将 Tomcat 放在 Apache 服务器后面,并使用 Apache 模块来执行 NTLM 身份验证。

Spring 3 和 NTLM 身份验证

于 2013-10-02T08:02:53.780 回答
0

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

于 2013-10-03T00:54:29.797 回答