SSLHandshakeException:不存在主题替代名称

我正在通过java代码调用HTTPS SOAP Web服务。 我已经在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的主机名与cert中提供的CN的主机名不匹配。 我阅读了一个在这里定义自定义主机名validation者的解决方法。 但我无法在我的代码中实现解决方法。

 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。 如果这个exception可以解决一些不同的解决方法,请提出build议。

谢谢,布鲁诺给我提供了常用名和主题别名。 因为我们发现证书是使用networking的DNS名称的CN生成的,并要求使用“主题备用名称”条目(即san = ip:10.0.0.1)重新生成新证书。 这是实际的解决scheme

但是,我们设法find了一个可以在开发阶段运行的解决方法 。 只需在我们正在进行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")); } 

与一些浏览器不同,Java在服务器身份validation(RFC 2818,第3.1节)和IP地址方面严格遵循HTTPS规范。

使用主机名时,可能会退回到服务器证书的主题DN中的通用名称,而不是使用“主题备用名称”。

使用IP地址时,证书中必须有一个“主题备用名称”条目(IP地址types,不是DNS名称)。

你会find更多关于规范的细节,以及如何在这个答案中生成这样的证书。