SSLHandshakeException: нет альтернативных имен объектов
Я вызываю веб-службу HTTPS SOAP через Java-код. Я уже импортировал самозаверяющий сертификат в jre cacerts keystore. Теперь я получаю:
com.sun.xml.internal.ws.com.client.ClientTransportException: HTTP transport error: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present
Имя хоста URL-адреса службы не соответствует имени CN, указанному в сертификате. Я прочитал об обходном пути определения настраиваемого верификатора хоста здесь. Но я не могу сделать, где я должен использовать обходной путь в своем коде.
public SOAPMessage invokeWS(WSBean bean) throws Exception {
SOAPMessage response=null;
try{
/** Create a service and add at least one port to it. **/
String targetNameSpace = bean.getTargetNameSpace();
String endpointUrl = bean.getEndpointUrl();
QName serviceName = new QName(targetNameSpace, bean.getServiceName());
QName portName = new QName(targetNameSpace, bean.getPortName());
String SOAPAction = bean.getSOAPAction();
HashMap<String, String> map = bean.getParameters();
Service service = Service.create(serviceName);
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl);
/** Create a Dispatch instance from a service. **/
Dispatch dispatch = service.createDispatch(portName, SOAPMessage.class,
Service.Mode.MESSAGE);
// The soapActionUri is set here. otherwise we get a error on .net based
// services.
dispatch.getRequestContext().put(Dispatch.SOAPACTION_USE_PROPERTY,
new Boolean(true));
dispatch.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY,
SOAPAction);
/** Create SOAPMessage request. **/
// compose a request message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
// Create objects for the message parts
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
SOAPElement bodyElement = body.addChildElement(bean.getInputMethod(),
bean.getPrefix(), bean.getTargetNameSpace());
...more code to form soap body goes here
// Print request
message.writeTo(System.out);
// Save the message
message.saveChanges();
response = (SOAPMessage)dispatch.invoke(message);
}
catch (Exception e) {
log.error("Error in invokeSiebelWS :"+e);
}
return response;
}
Пожалуйста, проигнорируйте параметр WSBean, поскольку пространства имен и другие атрибуты wsdl поступают из этого bean. И если это исключение может быть разрешено с помощью некоторых обходных решений, pls действительно предлагают.
Ответы
Ответ 1
Спасибо, Бруно за то, что он дал мне хедз-ап по имени и названию альтернативного имени. Поскольку мы выяснили, что сертификат был сгенерирован CN с DNS-именем сети и попросил обновить новый сертификат с помощью записи "Альтернативное имя субъекта", т.е. San = ip: 10.0.0.1. который является фактическим решением.
Но нам удалось найти обходной путь, с которым мы можем работать на этапе разработки. Просто добавьте статический блок в класс, из которого мы создаем соединение ssl.
static {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
{
public boolean verify(String hostname, SSLSession session)
{
// ip address of the service URL(like.23.28.244.244)
if (hostname.equals("23.28.244.244"))
return true;
return false;
}
});
}
Если вы используете Java 8, существует гораздо более гладкий способ достижения такого же результата:
static {
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equals("127.0.0.1"));
}
Ответ 2
В отличие от некоторых браузеров, Java следует спецификации HTTPS строго, когда дело доходит до проверки подлинности сервера (RFC 2818, раздел 3.1) и IP-адресов.
При использовании имени хоста можно отказаться от общего имени в имени субъекта сертификата сервера вместо использования альтернативного имени темы.
При использовании IP-адреса в сертификате должна быть запись альтернативного имени объекта (типа IP-адрес, а не имя DNS).
Более подробную информацию о спецификации и о том, как создать такой сертификат в вы найдете ниже.