Java 6 NTLM 代理身份验证和 HTTPS - 有人让它工作吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1326849/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:18:50  来源:igfitidea点击:

Java 6 NTLM proxy authentication and HTTPS - has anyone got it to work?

javaproxyjax-wsntlmsquid

提问by DavidK

I have a Java application (not an applet) that needs to access a web service. Proxies for the web service have been generated with JAX-WS, and seem to work fine. In one scenario it needs to talk through a web proxy server (actually Squid 3.0), which is set to require NTLM authentication.

我有一个需要访问 Web 服务的 Java 应用程序(不是小程序)。Web 服务的代理已使用 JAX-WS 生成,并且似乎工作正常。在一种情况下,它需要通过 Web 代理服务器(实际上是 Squid 3.0)进行通信,该服务器设置为需要 NTLM 身份验证。

Running on Sun's JRE 1.6.0_14, everything works fine for accessing HTTP URLs, without requiring any changes: the built-in NTLM authenticator kicks in and it all works seemlessly. If, however, the web service URL is a HTTPS URL, the web service call fails deep inside Sun's code:

在 Sun 的 JRE 1.6.0_14 上运行,一切都可以正常访问 HTTP URL,无需任何更改:内置 NTLM 身份验证器启动,并且一切正常。但是,如果 Web 服务 URL 是 HTTPS URL,则 Web 服务调用将在 Sun 代码的深处失败:

com.sun.xml.internal.ws.client.ClientTransportException: HTTP transport error: java.lang.NullPointerException
        at com.sun.xml.internal.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:121)
        at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:142)
        at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:83)
        at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:105)
        at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:587)
        at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:546)
        at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:531)
        at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:428)
        at com.sun.xml.internal.ws.client.Stub.process(Stub.java:211)
        at com.sun.xml.internal.ws.client.sei.SEIStub.doProcess(SEIStub.java:124)
        at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:98)
        at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
        at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
        ... our web service call ...
Caused by: java.lang.NullPointerException
        at sun.net.www.protocol.http.NTLMAuthentication.setHeaders(NTLMAuthentication.java:175)
        at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:1487)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:164)
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:896)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
        at com.sun.xml.internal.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:109)
        ... 16 more

Looking in Sun's bug database turns up a few exceptions in such classes, but all of them seem to have been fixed. Has anyone come across anything like this? Has anyone got this to work?

在 Sun 的 bug 数据库中查找此类类中的一些异常,但似乎所有异常都已修复。有没有人遇到过这样的事情?有没有人让这个工作?

回答by Zack Angelo

Are you married to JAX-WS? I use Apache Axis2, which uses the commons httpclient and has NTLM authentication built-in.

你和 JAX-WS 结婚了吗?我使用 Apache Axis2,它使用 commons httpclient 并内置 NTLM 身份验证。

Example:

例子:

//Configure SOAP HTTP client to authenticate to server using NTLM
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();

//TODO make report server credentials configurable
auth.setUsername("jdoe");
auth.setPassword("strongpass");
auth.setDomain("WINDOWSDOMAIN");
auth.setHost("host.mydomain.com");
auth.setPort(443);

Options o = new Options();
o.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE,auth);
myWebServiceStub._getServiceClient().setOptions(o);

回答by DavidK

After some debugging, this seems to be a flaw in the JRE class libraries, specifically in sun.net.www.protocol.http.HttpURLConnection.

经过一些调试,这似乎是 JRE 类库中的一个缺陷,特别是在sun.net.www.protocol.http.HttpURLConnection.

Studying the HTTP requests and responses in the cases of HTTP and HTTPS endpoints showed that, in the successful HTTP case, the requests had a header Proxy-Connection=keep-alive, which was missing on the failing HTTPS case. Reading more generally, there seems to be some confusion on whether one should use "Proxy-Connection" or just "Connection", too ...

研究 HTTP 和 HTTPS 端点情况下的 HTTP 请求和响应表明,在成功的 HTTP 情况下,请求有一个 header Proxy-Connection=keep-alive,而在失败的 HTTPS 情况下则没有。更一般地阅读,对于是否应该使用“代理连接”或仅使用“连接”似乎有些混乱......

Anyway, it is notable that in the HTTP case, the code goes through HttpURLConnection.writeRequests(), which contains the following code snippet

无论如何,值得注意的是,在 HTTP 的情况下,代码通过HttpURLConnection.writeRequests(),其中包含以下代码片段

    /*
     * For HTTP/1.1 the default behavior is to keep connections alive.
     * However, we may be talking to a 1.0 server so we should set
     * keep-alive just in case, except if we have encountered an error
     * or if keep alive is disabled via a system property
     */

    // Try keep-alive only on first attempt
    if (!failedOnce && http.getHttpKeepAliveSet()) {
    if (http.usingProxy) {
        requests.setIfNotSet("Proxy-Connection", "keep-alive");
    } else {
        requests.setIfNotSet("Connection", "keep-alive");
    }

There's no such code when creating a tunnel through the proxy for HTTPS, which causes Squid to get upset during the NTLM authentication conversation.

在通过 HTTPS 代理创建隧道时没有这样的代码,这会导致 Squid 在 NTLM 身份验证对话期间感到不安。

To work around this, in HttpURLConnection.sendCONNECTRequest(), I added

为了解决这个问题HttpURLConnection.sendCONNECTRequest(),我添加了

if (http.getHttpKeepAliveSet()) {
    if (http.usingProxy) {
        requests.setIfNotSet("Proxy-Connection", "keep-alive");
    }
}

just before

就在之前

setPreemptiveProxyAuthentication(requests);
http.writeRequests(requests, null);

I inject my modified HttpURLConnection.classinto the JRE using the "-Xbootclasspath/p" flag, and now it works! Not exactly elegant, but there we are.

HttpURLConnection.class使用“-Xbootclasspath/p”标志将我的修改注入 JRE,现在它可以工作了!不完全优雅,但我们就是这样。