使用 NTLM 进行身份验证时,HttpClient 4.1.1 返回 401,浏览器工作正常
我正在尝试使用 Apache/Jakarta HttpClient 4.1.1 使用给定的凭据连接到任意网页。为了测试这一点,我在我的开发机器上安装了 IIS 7.5 的最小安装,一次只有一种身份验证模式处于活动状态。基本身份验证工作正常,但每当我尝试登录时,Digest 和 NTLM 都会返回 401 错误消息。这是我的代码:
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost/");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new NTCredentials("user", "password", "", "localhost"));
if (!new File(System.getenv("windir") + "\\krb5.ini").exists()) {
List<String> authtypes = new ArrayList<String>();
authtypes.add(AuthPolicy.NTLM);
authtypes.add(AuthPolicy.DIGEST);
authtypes.add(AuthPolicy.BASIC);
httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF,
authtypes);
httpclient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF,
authtypes);
}
localContext.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
HttpResponse response = httpclient.execute(httpget, localContext);
System.out.println("Response code: " + response.getStatusLine());
我在 Fiddler 中注意到的一件事是 Firefox 与 HttpClient 发送的哈希值不同,这让我思考也许 IIS 7.5 期望比 HttpClient 提供更强的散列?有什么想法吗?如果我能验证这是否适用于 NTLM,那就太好了。摘要也很好,但如果有必要的话,没有它我也能生活。
I'm trying to use the Apache/Jakarta HttpClient 4.1.1 to connect to an arbitrary web page using the given credentials. To test this, I have a minimal install of IIS 7.5 on my dev machine running where only one authentication mode is active at a time. Basic authentication works fine, but Digest and NTLM return 401 error messages whenever I try to log in. Here is my code:
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost/");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new NTCredentials("user", "password", "", "localhost"));
if (!new File(System.getenv("windir") + "\\krb5.ini").exists()) {
List<String> authtypes = new ArrayList<String>();
authtypes.add(AuthPolicy.NTLM);
authtypes.add(AuthPolicy.DIGEST);
authtypes.add(AuthPolicy.BASIC);
httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF,
authtypes);
httpclient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF,
authtypes);
}
localContext.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
HttpResponse response = httpclient.execute(httpget, localContext);
System.out.println("Response code: " + response.getStatusLine());
The one thing I've noticed in Fiddler is that the hashes sent by Firefox versus by HttpClient are different, making me think that maybe IIS 7.5 is expecting stronger hashing than HttpClient provides? Any ideas? It'd be great if I could verify that this would work with NTLM. Digest would be nice too, but I can live without that if necessary.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我不是该主题的专家,但在使用 http 组件进行 NTLM 身份验证期间,我发现客户端需要 3 次尝试才能连接到我的情况下的 NTML 端点。 此处对 Spnego 进行了描述但对于 NTLM 身份验证来说有点不同。
对于 NTLM,第一次尝试客户端将发出
目标身份验证状态:UNCHALLENGED
的请求,Web 服务器返回 HTTP 401 状态和标头:WWW-Authenticate: NTLM
客户端将检查对于配置的身份验证方案,应在客户端代码中配置 NTLM。
第二次尝试,客户端将发出
目标身份验证状态:CHALLENGED
的请求,并将发送一个授权标头,其中包含以 Base64 格式编码的令牌:授权:NTLM TlRMTVNTUAABAAAAAYIIogAAAAAAoAAAAAAAAACgAAAAFASgKAAAADw==
服务器再次返回 HTTP 401 状态,但标头:
WWW-Authenticate: NTLM
现在已填充编码信息。第三次尝试客户端将使用
WWW-Authenticate: NTLM
标头中的信息,并使用目标身份验证状态:HANDSHAKE
和授权标头Authorization: NTLM 发出最终请求
其中包含服务器的更多信息。就我而言,此后我会收到
HTTP/1.1 200 OK
。为了避免每个请求中的所有这些文档<第 4.7.1 章中的 /a> 指出,逻辑相关的请求必须使用相同的执行令牌。对我来说它不起作用。
我的代码:
我在 EJB 的 @PostConstruct 方法中初始化客户端一次
在每个请求中使用相同的客户端实例:
在 EJB 的 @PreDestroy 方法中释放资源并将连接返回到连接管理器:
I am not an expert on the subject but during the NTLM authentication using http components I have seen that the client needs 3 attempts in order to connect to an NTML endpoint in my case. It is kinda described here for Spnego but it is a bit different for the NTLM authentication.
For NTLM in the first attempt client will make a request with
Target auth state: UNCHALLENGED
and Web server returns HTTP 401 status and a header:WWW-Authenticate: NTLM
Client will check for the configured Authentication schemes, NTLM should be configured in client code.
Second attempt, client will make a request with
Target auth state: CHALLENGED
, and will send an authorization header with a token encoded in base64 format:Authorization: NTLM TlRMTVNTUAABAAAAAYIIogAAAAAoAAAAAAAAACgAAAAFASgKAAAADw==
Server again returns HTTP 401 status but the header:
WWW-Authenticate: NTLM
now is populated with encoded information.3rd Attempt Client will use the information from
WWW-Authenticate: NTLM
header and will make the final request withTarget auth state: HANDSHAKE
and an authorisation headerAuthorization: NTLM
which contains more information for the server.In my case I receive an
HTTP/1.1 200 OK
after that.In order to avoid all this in every request documentation at chapter 4.7.1 states that the same execution token must be used for logically related requests. For me it did not worked.
My code:
I initialize the client once in a
@PostConstruct
method of an EJBUse the same client instance in every request:
Deallocate the resources and return the connection back to connection manager, at the @PreDestroy method of my EJB:
我发现解决此类情况的最简单方法是 Wireshark。这是一把非常大的锤子,但它确实会向您展示一切。安装它,确保您的服务器位于另一台计算机上(不适用于本地主机)并开始日志记录。
运行失败的请求,运行有效的请求。然后,按http过滤(只需将http放在过滤字段中),找到第一个GET请求,找到另一个GET请求并进行比较。确定有意义的差异,您现在有特定的关键字或问题需要搜索代码/网络。如果还不够,请缩小到第一个 TCP 会话并查看完整的请求/响应。与另一件相同。
我用这种方法解决了令人难以置信的大量问题。 Wireshark 是一个非常有用的工具,需要了解。大量超高级功能,让您的网络调试更加轻松。
您还可以在客户端或服务器端运行它。无论什么都会向您显示两个请求,以便您进行比较。
The easiest way troubleshoot such situations I found is Wireshark. It is a very big hammer, but it really will show you everything. Install it, make sure your server is on another machine (does not work with Localhost) and start logging.
Run your request that fails, run one that works. Then, filter by http (just put http in the filter field), find the first GET request, find the other GET request and compare. Identify meaningful difference, you now have specific keywords or issues to search code/net for. If not enough, narrow down to first TCP conversation and look at full request/response. Same with the other one.
I solved an unbelievable number of problems with that approach. And Wireshark is very useful tool to know. Lots of super-advanced functions to make your network debugging easier.
You can also run it on either client or server end. Whatever will show you both requests to allow you to compare.
我在 HttpClient 4.1.2 中遇到了类似的问题。对我来说,通过恢复到 HttpClient 4.0.3 解决了这个问题。我永远无法使用内置实现或使用 JCIFS 让 NTLM 与 4.1.2 一起工作。
I had a similar problem with HttpClient 4.1.2. For me, it was resolved by reverting to HttpClient 4.0.3. I could never get NTLM working with 4.1.2 using either the built-in implementation or using JCIFS.
更新我们的应用程序以使用 httpcomponents-client-4.5.1 中的 jar 解决了我的这个问题。
Updating our application to use the jars in the httpcomponents-client-4.5.1 resolved this issue for me.
我终于想通了。摘要式身份验证要求,如果您在请求中使用完整 URL,则代理也需要使用完整 URL。我没有在示例中留下代理代码,但它被定向到“localhost”,这导致它失败。将其更改为 127.0.0.1 即可正常工作。
I finally figured it out. Digest authentication requires that if you use a full URL in the request, the proxy also needs to use the full URL. I did not leave the proxy code in the sample, but it was directed to "localhost", which caused it to fail. Changing this to 127.0.0.1 made it work.