我正在阅读这个article,在它的帮助下,我能够找到访问我的JSP页面的机器的用户名,域名和主机名,但我仍然无法理解如何验证用户。因为在我访问JSP页面并尝试输入正确的用户名但密码错误的Firefox中,它会对用户进行身份验证。
因此,主要关注的是如何使用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 + " ");
答案 0 :(得分:1)
在下面的线程中,他们将Tomcat放在Apache服务器后面并使用Apache模块执行NTLM身份验证。
答案 1 :(得分:1)
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服务器,但我可能会弄错。
答案 2 :(得分:0)
您所要做的就是按照this article启用Firefox以使用像IE和Chrome那样的NTLM!