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


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

在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

查看Sun的bug数据库会在这些类中出现一些例外情况,但所有这些异常似乎都已得到修复。有没有人遇到过这样的事情?有人有这个工作吗?


8633
2017-08-25 08:32


起源

请提供您的进口商品吗? - itro


答案:


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

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

无论如何,值得注意的是,在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");
    }

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

要解决这个问题,请参阅 HttpURLConnection.sendCONNECTRequest(),我补充道

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

就在此之前

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

我注入我修改过的 HttpURLConnection.class 使用“-Xbootclasspath / p”标志进入JRE,现在它可以正常工作!不完全优雅,但我们有。


10
2017-08-26 14:33



我遇到了同样的问题。我发现了一个描述完全相同问题的JDK错误: bugs.sun.com/view_bug.do?bug_id=6206466  奇怪的是,它被标记为重复/固定,虽然另一个错误是完全不同的。 - sereda
是的,有时我不确定Sun的bug数据库是否让我想笑或哭。可能他们太忙于担心如果拉里埃里森要解雇他们或不检查错误是否真的重复...... - DavidK
BigZig你能提供你的进口吗? - itro
(几年后......)在错误报告中提到了这个问题: bugs.java.com/view_bug.do?bug_id=6973030 自Java 7b109以来,这被标记为已修复。 - Bruno


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

例:

//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);

4
2017-08-25 14:34



这个项目有点太接近了,让我不得不扯掉JAX-WS并用一些东西替换它,但感谢你的建议。 - DavidK