Проверка подлинности прокси-сервера Java 6 NTLM и HTTPS - у кого-нибудь получилось? - PullRequest
12 голосов
/ 25 августа 2009

У меня есть приложение Java (не апплет), которому требуется доступ к веб-службе. Прокси-серверы для веб-службы были сгенерированы с помощью JAX-WS и, похоже, работают нормально. В одном сценарии он должен общаться через веб-прокси-сервер (на самом деле Squid 3.0), для которого требуется проверка подлинности NTLM.

Работая на Sun JRE 1.6.0_14, все работает нормально для доступа к HTTP-URL-адресам, не требуя каких-либо изменений: встроенный аутентификатор NTLM включается, и все работает без всяких проблем Однако если URL-адрес веб-службы является URL-адресом HTTPS, вызов веб-службы завершается неудачно в коде 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 обнаруживает несколько исключений в таких классах, но все они, похоже, исправлены. Кто-нибудь сталкивался с чем-нибудь подобным? Кто-нибудь заставил это работать?

Ответы [ 2 ]

11 голосов
/ 26 августа 2009

После некоторой отладки это кажется недостатком в библиотеках классов JRE, особенно в sun.net.www.protocol.http.HttpURLConnection.

Изучение запросов и ответов HTTP в случаях конечных точек HTTP и HTTPS показало, что в успешном случае HTTP запросы имели заголовок Proxy-Connection=keep-alive, который отсутствовал в случае сбоя HTTPS. Если читать в более общем плане, то возникает некоторая путаница относительно того, следует ли использовать «Proxy-Connection» или просто «Connection» тоже ...

В любом случае, примечательно, что в случае 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", и теперь он работает! Не совсем элегантно, но мы здесь.

4 голосов
/ 25 августа 2009

Вы женаты на JAX-WS? Я использую Apache Axis2, который использует httpclient commons и имеет встроенную аутентификацию 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);
...