Дополнительное введение
Быстрое информативное введение проблемы было предоставлено @cocorossello в своем ответе. Я только добавлю, что все было начато из Java Mailing List здесь>> .
Это сообщение также включает быстрый пример для воспроизведения «проблемы»:
import java.net.URL;
import java.io.InputStream;
public class Fetch {
public static void main(final String[] args) throws Exception {
final URL targetURL = new URL("https://repository.jboss.org/nexus/content/groups/public/javax/media/jai-core/1.1.3/jai-core-1.1.3.pom");
try (final InputStream is = targetURL.openConnection().getInputStream()) {
is.read();
}
System.out.println("Done");
}
}
Решение на стороне клиента:
Проблемаотносящиеся к JSSE ( Java Secure Socket Extension ) модуль / библиотека - внутренняя реализация Java для защищенных SSL / TLS соединений.
ВРЕМЕННОЕ РЕШЕНИЕ : Таким образом, чтобы обойти эту проблему, нам нужно использовать различные реализации SSL / TLS , например, BouncyCastle
Я создал небольшой проект в GitHub в качестве подтверждения концепции: jdk11-server_hello-workaround , основной класс - FetchWorkaround.java
,который выглядит так:
import org.bouncycastle.crypto.tls.*;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.security.SecureRandom;
public class FetchWorkaround {
private static final String HOST = "repository.jboss.org";
private static final int PORT = 443;
private static final String RESOURCE = "/nexus/content/groups/public/javax/media/jai-core/1.1.3/jai-core-1.1.3.pom";
public static void main(String[] args) throws Exception {
TlsClientProtocol protocol = getTlsClientProtocol();
sendRequest(protocol);
readResponseStream(protocol.getInputStream());
}
private static void readResponseStream(InputStream input) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (TlsNoCloseNotifyException exception) {
// do nothing
}
}
private static void sendRequest(TlsClientProtocol protocol) throws IOException {
OutputStream output = protocol.getOutputStream();
output.write(("GET " + RESOURCE + " HTTP/1.1\r\n").getBytes("UTF-8"));
output.write(("Host: " + HOST + "\r\n").getBytes("UTF-8"));
output.write("Connection: close\r\n".getBytes("UTF-8")); // To force socket close immediately.
output.write("\r\n".getBytes("UTF-8")); // HTTP 1.1 requirement: last line must be empty line.
output.flush();
}
private static TlsClientProtocol getTlsClientProtocol() throws IOException {
SecureRandom secureRandom = new SecureRandom();
Socket socket = new Socket(InetAddress.getByName(HOST), PORT);
TlsClientProtocol protocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), secureRandom);
DefaultTlsClient client = new DefaultTlsClient() {
public TlsAuthentication getAuthentication() throws IOException {
TlsAuthentication auth = new TlsAuthentication() {
public void notifyServerCertificate(Certificate serverCertificate) throws IOException {
}
public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException {
return null;
}
};
return auth;
}
};
protocol.connect(client);
return protocol;
}
}
Он подключается к хосту (тот из Fetch.java
), используя сокет, определяя TlsClientProtocol
и отправляет запрос GET
на требуемый ресурс (тот же pom.xml ), вывод выглядит так:
HTTP/1.1 200 OK
Date: Wed, 26 Sep 2018 04:40:54 GMT
Server: Nexus/2.14.6-02
<... other headers ...>
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
<... etc ...>
<groupId>javax.media</groupId>
<artifactId>jai-core</artifactId>
<version>1.1.3</version>
<... etc ...>
Итак, pom.xml был успешно выбран.
Дополнительная информация
PoC показывает, что можно решить проблему, связанную с server_hello на стороне клиента, но это можетбыть трудоемким (особенно для замены эфира связанной логики).
В ответе на этот вопрос >> показано, какзагрузка двоичных данных с помощью сокетов - просто вспомогательный метод для обработки заголовков в верхней части ответа.
[Требуется доступ к ВМ] Здесь >> - руководство по настройке Bouncy Castle Provider на уровне Java .
[Требуется доступ к ВМ] В случае, если возможно обновить JDK на стороне виртуальной машины (build / CI) - разумно было бы просто сделать пользовательскую JDK сборку с помощьюисправление ошибки PATCH >> - влияет только на класс sun.security.ssl.SSLExtensions
- или просто с помощью связанной структуры источников >>