1

我想使用 NTLM 为 DefaultHttpClient 实现抢先式身份验证。我从Dan Hounshell找到了一个库,它可以正常进行身份验证。

但我无法弄清楚如何通过抢先身份验证来实现这一点。我用这个很酷的答案找到了使用 Apache HttpClient 4 的 Preemptive Basic authentication问题:

UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
HttpRequest request = ...
request.addHeader(new BasicScheme().authenticate(creds, request));

不适合我的问题,但一个好主意。所以我尝试使用NTLMSchemeFactory创建一个新实例AuthSchemewith 给了我这个authenticate功能。

NTCredentials ntc = new NTCredentials("example.com/user:pwd");
httpPost.addHeader(new NTLMScheme(new JCIFSEngine()).authenticate(ntc, httpPost));

当这个函数被调用时,我会得到一个异常:

org.apache.http.auth.AuthenticationException:意外状态:未初始化

我该如何解决?

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=...

我认为第一个请求绝对没用。

4

2 回答 2

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...跳过初始请求的标头。在第一次使用此标头后,此标头会自行删除,以避免此虚拟标头覆盖真正的身份验证过程。这对我有用。

于 2012-12-13T08:39:42.337 回答
-1

NTLM 身份验证不能抢先执行。这是一个复杂的方案,涉及多 (3) 次消息交换。

于 2012-12-12T14:32:46.920 回答