同时使用 SSL 加密和 NTLM 身份验证的 HttpClient 失败

Posted

技术标签:

【中文标题】同时使用 SSL 加密和 NTLM 身份验证的 HttpClient 失败【英文标题】:HttpClient using both SSL encryption and NTLM authentication fails 【发布时间】:2012-03-15 05:48:48 【问题描述】:

我正在尝试在使用 SSL 加密 (https) 以及 NTLM 身份验证的 Sharepoint 2010 服务器上执行简单的 REST 调用。当服务器设置为不需要 SSL(仅用于测试,服务器将在生产中需要 SSL),我的 NTLM 身份验证和后续 REST 调用使用 HttpClient 可以正常工作。但是,启用 SSL 后,身份验证将不再起作用。

这是 SSL 处理的代码(设置为接受所有证书):

    SSLContext sslContext = SSLContext.getInstance("TLS");

    // set up a TrustManager that trusts everything
    sslContext.init(null, new TrustManager[]  new X509TrustManager() 
        public X509Certificate[] getAcceptedIssuers() 
            return null;
        

        public void checkClientTrusted(X509Certificate[] certs,
                String authType)  

        public void checkServerTrusted(X509Certificate[] certs,
                String authType)  
     , new SecureRandom());

    SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    Scheme httpsScheme = new Scheme("https", 443, sf);
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(httpsScheme);

    ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);

接下来是执行 NTML 和 HTTP GET 调用的代码:

    HttpParams params = new BasicHttpParams();

    DefaultHttpClient httpclient = new DefaultHttpClient(cm, params);

            // Set up the NTLM credentials
    NTCredentials creds = new NTCredentials(USERNAME, PASSWORD, MACHINE, DOMAIN);
    httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);

            // Setup the HTTP GET and execute it
    HttpHost target = new HttpHost(HOSTNAME, 443, "https");

    HttpContext localContext = new BasicHttpContext();
    HttpGet httpget = new HttpGet("/site/_vti_bin/ListData.svc/TestList");
    HttpResponse response1 = httpclient.execute(target, httpget, localContext);

我总是得到的回应是:

 HTTP/1.1 400 Bad Request
 The server encountered an error processing the request. See server logs for more details.

请注意,我已经使用 FireFox Poster 和 CURL 来执行我在此处以编程方式尝试执行的相同操作,并且效果很好。所以服务器似乎设置正确。

感谢您的宝贵时间!

【问题讨论】:

那么您被引导查看的服务器日志中有什么内容? 【参考方案1】:

为可能遇到此问题的其他人记录此问题。

问题在于 IIS 服务器设置为允许匿名登录。显然,如果设置了这个错误,那么在该安装下到共享点实例的任何 REST 或 SOAP 连接都不会成功。看起来好像字符串“anonymous”被添加到 REST/SOAP URL 中,这当然使它指向一个不存在的服务。在我们关闭允许在 IIS 实例上匿名登录后,调用工作。

【讨论】:

【参考方案2】:

我的猜测是由于 SSL 连接不持久,NTLM 身份验证失败。 NTLM 方案需要多次消息交换,并且只能与持久连接一起使用。

如果您发布 HTTP 会话的线路/上下文日志(在此处或 httpclient-users 列表中),我应该能够说出 SSL 连接不保持正常的原因。

【讨论】:

这种情况不应给出 400,因为关闭前的最后一个响应应该是带有 WWW-Authenticate 标头的 403。 @Edward Thomson:我有 IIS 服务器做各种奇怪的事情。直到有会话的线日志可以看到我们只能做出猜测。

以上是关于同时使用 SSL 加密和 NTLM 身份验证的 HttpClient 失败的主要内容,如果未能解决你的问题,请参考以下文章

Active Directory 和 NTLM 身份验证

NTLM 和自动匿名身份验证 IIS

BizTalk 发送端口与 NTLM 身份验证和自定义用户和密码

Thawte SSL Web Server

如何使用参数(通过 HTTP)向 NTLM 进行身份验证?

Python 中的 NTLM 身份验证