代码之家  ›  专栏  ›  技术社区  ›  DavidK

Java6NTLM代理身份验证和HTTPS-有人可以使用它吗?

  •  11
  • DavidK  · 技术社区  · 15 年前

    我有一个需要访问web服务的Java应用程序(不是小程序)。web服务的代理是用JAX-WS生成的,似乎工作得很好。在一个场景中,它需要通过一个web代理服务器(实际上是squid3.0)进行通信,该服务器被设置为需要NTLM身份验证。

    运行在Sun的JRE 1.6.0_上,一切都可以很好地访问httpurl,无需任何更改:内置的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数据库中查找这些类中的一些异常,但它们似乎都已修复。有人遇到过这样的事吗?有人用这个吗?

    2 回复  |  直到 15 年前
        1
  •  11
  •   Ian R. O'Brien Mamedov    9 年前

    经过一些调试后,这似乎是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 在JRE中使用“-Xbootclasspath/p”标志,现在它可以工作了!不太优雅,但我们到了。

        2
  •  4
  •   Zack Angelo    15 年前

    例子:

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