Я пытаюсь открыть http-соединение с URL-адресом, защищенным с помощью схемы аутентификации NTLM. Этот код работает правильно в течение 2 лет, когда мы были на Java 6. Я написал небольшую программу java, которая обращается к этому конкретному URL-адресу, чтобы сделать тестовый пример максимально простым.
Проблема в том, что я не могу заставить программу работать в Linux и при использовании версий JDK 7. Java пытается 20 раз получить доступ к URL-адресу, а затем я получаю сообщение об ошибке, указывающее, что сервер перенаправлен слишком много раз. Он отлично работает с linux и JDK 6, а в Windows 7 с JDK 6 или 7.
Я проверил и попробовал приведенное здесь решение (и многие другие): Получение "java.net.ProtocolException: сервер перенаправлен слишком много раз" Ошибка. Это не сработало. Я также должен добавить, что при доступе к URL-адресу из браузера я вижу, что куки файлы не задействованы.
Вот точная информация о версиях os/java, которые я пробовал:
Success
- Windows 7: среда выполнения Java (TM) SE (сборка 1.7.0_15-b03) (64-разрядная версия)
- Windows 7: среда выполнения Java (TM) SE (сборка 1.7.0_10-b18) (64-разрядная версия)
- Windows 7: среда выполнения Java (TM) SE (сборка 1.6.0_33-b04) (64-разрядная версия)
- Redhat enterprise linux 6.4: среда выполнения Java (TM) SE (сборка 1.6.0_33-b04) (64-разрядная версия)
Сбой:
- Redhat enterprise linux 6.4: среда выполнения Java (TM) SE (сборка 1.7.0-b147) (64-разрядная версия)
- Redhat enterprise linux 6.4: среда выполнения Java (TM) SE (сборка 1.7.0_05-b06) (64-разрядная версия)
- Redhat enterprise linux 6.4: среда выполнения Java (TM) SE (сборка 1.7.0_13-b20) (64-разрядная версия)
- Redhat enterprise linux 6.4: среда выполнения Java (TM) SE (сборка 1.7.0_15-b03) (64-разрядная версия)
Когда программа работает, я вижу используемые методы проверки подлинности и документ, который я пытаюсь загрузить в качестве вывода:
Scheme:Negotiate
Scheme:ntlm
.... document content ....
Done
Когда он терпит неудачу, у меня есть следующий вывод:
Scheme:Negotiate
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
Scheme:ntlm
java.net.ProtocolException: Server redirected too many times (20)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1635)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at TestWs.testWs(TestWs.java:67)
at TestWs.main(TestWs.java:20)
Вот исходный код программы:
package com.test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;
public class TestWs {
public static void main(String[] args) throws Exception {
new TestWs().testWs();
}
public void testWs() {
try {
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
Authenticator.setDefault(new MyAuthenticator("username", "password"));
URL url = new URL("https://someurlprotectedbyntlmauthentication.com");
URLConnection connection = url.openConnection();
InputStream is = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
while (true) {
String s = br.readLine();
if (s == null)
break;
System.out.println(s);
}
System.out.println("Done");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
class MyAuthenticator extends Authenticator {
private String httpUsername;
private String httpPassword;
public MyAuthenticator(String httpUsername, String httpPassword) {
this.httpUsername = httpUsername;
this.httpPassword = httpPassword;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
System.out.println("Scheme:" + getRequestingScheme());
return new PasswordAuthentication(httpUsername, httpPassword.toCharArray());
}
}
Любая помощь будет принята с благодарностью.
UPDATE:
После еще нескольких исследований я обнаружил, что аутентификация работает, если я использую пользователя домена, но не если я использую локального пользователя.
Этот код из JDK 7 вызывает у меня проблемы (класс com.sun.security.ntlm.Client):
public byte[] type3(byte[] type2, byte[] nonce) throws NTLMException {
if (type2 == null || (v != Version.NTLM && nonce == null)) {
throw new NullPointerException("type2 and nonce cannot be null");
}
debug("NTLM Client: Type 2 received\n");
debug(type2);
Reader r = new Reader(type2);
byte[] challenge = r.readBytes(24, 8);
int inputFlags = r.readInt(20);
boolean unicode = (inputFlags & 1) == 1;
String domainFromServer = r.readSecurityBuffer(12, unicode);
if (domainFromServer != null) {
domain = domainFromServer;
}
Итак, поскольку сервер зарегистрирован в домене, он отправляет клиенту его домен как часть протокола NTLM. Java заменяет домен, который я пытаюсь принудительно изменять с помощью переменной "domainFromServer" каждый раз, и он терпит неудачу, поскольку пользователь существует на сервере, а не на домене сервера.
Я точно не знаю, что с этим делать.