我想使用NTLM为DefaultHttpClient实现抢先认证。我发现了一个来自Dan Hounshell的库,它可以正常进行身份验证。
但我无法弄清楚如何使用抢先身份验证来完成这项工作。我发现问题Preemptive Basic authentication with Apache HttpClient 4有这个很酷的answer:
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
HttpRequest request = ...
request.addHeader(new BasicScheme().authenticate(creds, request));
对我的问题不是很完美但是一个好主意。因此,我尝试使用NTLMSchemeFactory
创建AuthScheme
的新实例,并为其提供authenticate
函数。
NTCredentials ntc = new NTCredentials("example.com/user:pwd");
httpPost.addHeader(new NTLMScheme(new JCIFSEngine()).authenticate(ntc, httpPost));
调用此函数时,我会得到一个例外:
org.apache.http.auth.AuthenticationException:意外状态:UNINITIATED
我该如何解决?
POST /login/ HTTP/1.1
Content-Length: 21
Content-Type: application/x-www-form-urlencoded
Host: example.com
Connection: Keep-Alive
data=...
HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Wed, 12 Dec 2012 14:36:26 GMT
Content-Length: 1344
Much data...
POST /login/ HTTP/1.1
Content-Length: 21
Content-Type: application/x-www-form-urlencoded
Host: example.com
Connection: Keep-Alive
Authorization: NTLM AAABBBCCC...FFF==
data=...
我认为第一个请求绝对无用。
答案 0 :(得分:0)
我的解决方案是:
public class PreemptiveNTLMHeader implements Header {
private HttpRequest request;
private NTCredentials ntc;
public PreemptiveNTLMHeader(HttpRequest request, NTCredentials ntc) {
this.request = request;
this.ntc = ntc;
}
/* (non-Javadoc)
* @see org.apache.http.Header#getName()
*/
public String getName() {
return "Authorization";
}
/* (non-Javadoc)
* @see org.apache.http.Header#getValue()
*/
public String getValue() {
request.removeHeader(this);
try {
return "NTLM " + new JCIFSEngine().generateType1Msg(ntc.getDomain(), ntc.getWorkstation());
} catch(NTLMEngineException e) {
return "Failed";
}
}
/* (non-Javadoc)
* @see org.apache.http.Header#getElements()
*/
public HeaderElement[] getElements() throws ParseException {
return null;
}
}
有了这种用法:
NTCredentials ntc = new NTCredentials("example.com/user:password");
httpPost.addHeader(new PreemptiveNTLMHeader(httpPost, ntc));
DefaultHttpClient也会发送一个跳过初始请求的Authorization: NTLM AAA...
标头。在第一次使用此标头后,此标头将删除自身,以避免此虚拟标头覆盖真正的auth进程。这对我有用。
答案 1 :(得分:-1)
无法预先执行NTLM身份验证。这是一个涉及多个(3)消息交换的复杂方案。