【问题标题】:NTLM authentication works with curl, but not from JavaNTLM 身份验证适用于 curl,但不适用于 Java
【发布时间】:2017-10-29 21:50:21
【问题描述】:

我尝试连接到部署在 Windows Server 上的应用程序。 我使用 NTLM。我正在使用 Ubuntu 和 Java8。

我收到HTTP 401 代码,但前提是我尝试连接 来自我的 Java 应用程序。与 curl 请求完全相同 身份验证详细信息正常,我收到HTTP 200

curl -v -L --ntlm -u 'myuser\mydomain:mypass' 'http://myip/api/element/151

这是我的 Java 代码 (我稍微简化了一下,只包含与问题相关的内容):

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
...
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.glassfish.jersey.apache.connector.ApacheClientProperties;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
...
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.RequestEntityProcessing;
...

class MyConnector {

    private final Client client;
    ...

    protected ClientConfig prepareClientConfig() {
        ClientConfig config = new ClientConfig();
        config.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
        config.property(ClientProperties.FOLLOW_REDIRECTS, true);
        config.property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.BUFFERED);

        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new NTCredentials("myuser", "mypassword",
                "mydomain", "mydomain"));

        config.property(ApacheClientProperties.CREDENTIALS_PROVIDER, credentialsProvider);
        config.connectorProvider(new ApacheConnectorProvider());

        return config;
    }

    ...

    MyConnector(...) {

    ...
    client = ClientBuilder.newClient(prepareClientConfig());

    }


    protected String getDocString(...) throws MyException {

        WebTarget target = client.target("http://myipi/api").path("element/151");

        Invocation.Builder temp = target.request();
        Response response = target.request().get();

        if (response.getStatus() == Status.OK.getStatusCode()) {
            String docString = response.readEntity(String.class);

            return docString;
        }

        throw new MyException("Couldn't obtain doc. HTTP error code: " + response.getStatus());
    }

    ...
}

调用getDocString 函数需要 5-15 (!) 分钟。 我也相信应用程序会消耗异常大量的 RAM, 尽管没有同时运行其他功能(程序未并行化)。 然后我得到HTTP 401 代码。

当我的 Java 应用程序工作时,我遇到了一些情况。故事是:

  1. 我的应用程序在没有 NTLM 的情况下工作
  2. 我的同事在他们的应用程序中添加了 NTLM,我调整了代码,我的应用程序得到了401,我的 curl 请求得到了401
  3. 我从Ubuntu 14 LTS升级到Ubuntu 16.0.2 LTS,我的应用得到了200,curl得到了200
  4. 我提供了设置工作的服务器(我没有了)
  5. 我设置了一个新服务器,再次使用Ubuntu 16.0.2 LTS,我的应用程序得到了401,curl 得到了200
  6. 我升级到Ubuntu 17.04(非LTS),我的应用获得了一次200,但我不能 重现它,现在完全相同的请求得到401,curl 得到200

我知道这个问题: How to send NTLM authenticated post request using jersey? 我使用了代码,它允许我的应用程序与服务器升级结合使用(在点 3.)。 但我不知道如何让它再次工作。

我使用mitmproxy调试请求,输出如下 (我隐藏了Authorization/WWW-Authenticate 字段):

Proxy server listening at http://0.0.0.0:8080
127.0.0.1:39622: clientconnect
127.0.0.1:39622: request
  -> Request(GET /api/element/151)
127.0.0.1:39622: serverconnect
  -> myip:80
127.0.0.1:39622: response
  -> Response(401 Unauthorized, text/html, 1.26k)
127.0.0.1:39622: GET http://myip/api/element/151
    User-Agent: Jersey/2.26-b03 (Apache HttpClient 4.5.3)
    Host: myip
    Connection: Keep-Alive
    Accept-Encoding: gzip,deflate
 << 401 Unauthorized 1.26k
    Content-Type: text/html
    Server: Microsoft-IIS/8.5
    WWW-Authenticate: Negotiate
    WWW-Authenticate: NTLM
    X-Powered-By: ASP.NET
    Date: Mon, 29 May 2017 13:38:36 GMT
    Content-Length: 1293
127.0.0.1:39622: request
  -> Request(GET /api/element/151)
127.0.0.1:39622: response
  -> Response(401 Unauthorized, text/html; charset=us-ascii, 341b)
127.0.0.1:39622: GET http://myip/api/element/151
    User-Agent: Jersey/2.26-b03 (Apache HttpClient 4.5.3)
    Host: myip
    Connection: Keep-Alive
    Accept-Encoding: gzip,deflate
    Authorization: NTLM TlRAAA==
 << 401 Unauthorized 341b
    Content-Type: text/html; charset=us-ascii
    Server: Microsoft-HTTPAPI/2.0
    WWW-Authenticate: NTLM TlRAAABBBBBBAAA==
    Date: Mon, 29 May 2017 13:38:36 GMT
    Content-Length: 341
127.0.0.1:39622: request
  -> Request(GET /api/element/151)
127.0.0.1:39622: server communication error: TcpDisconnect('[Errno 104] Connection reset by peer',)
127.0.0.1:39622: serverdisconnect
  -> myip:80
127.0.0.1:39622: serverconnect
  -> myip:80
127.0.0.1:39622: response
  -> Response(401 Unauthorized, text/html, 1.26k)
127.0.0.1:39622: GET http://myip/api/element/151
    User-Agent: Jersey/2.26-b03 (Apache HttpClient 4.5.3)
    Host: myip
    Connection: Keep-Alive
    Accept-Encoding: gzip,deflate
    Authorization: NTLM TlRAAABBBDDDAAA==
 << 401 Unauthorized 1.26k
    Content-Type: text/html
    Server: Microsoft-IIS/8.5
    WWW-Authenticate: Negotiate
    WWW-Authenticate: NTLM
    X-Powered-By: ASP.NET
    Date: Mon, 29 May 2017 13:44:35 GMT
    Content-Length: 1293
127.0.0.1:39622: serverdisconnect
  -> myip:80
127.0.0.1:39622: clientdisconnect

我将非常感谢您对此发表任何评论。

更新:我也试过 Debian8 和 Debian9。结果是一样的。我得到了 401 广告 Debian8,更新到 Debian9,得到了一次 200,然后不断地得到了 401(对于完全相同的请求)。

【问题讨论】:

    标签: java ubuntu curl jersey ntlm


    【解决方案1】:

    我通过使用 JCIFS 库而不是来自 HttpClient 的默认 NTLM 身份验证解决了这个问题。您可以在 Apache 页面上查看示例: https://hc.apache.org/httpcomponents-client-4.5.x/ntlm.html

    问题是我找不到使它与泽西岛兼容的方法。 Jersey 使用javax.ws.rs.client.Client,我不知道如何更新它的 AuthScheme(没有设置它的方法)。所以我切换到org.apache.http.impl.client.CloseableHttpClient 并重写了整个应用程序以使用原始的 HttpClient 方法。

    【讨论】:

      猜你喜欢
      • 2011-10-09
      • 1970-01-01
      • 2016-11-11
      • 2014-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-18
      相关资源
      最近更新 更多