I was working with a web service from a site that uses SSL with a certificate that was self-signed. When attempting to make the calls, I received the error:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching {web address} found
The workaround for this issue is to provide a HostnameVerifer that skips the host name verification process. There is an example of how to do this here.
I ran into this issue after I had a nice clean codebase using Spring’s WebServiceTemplate and RestTemplate. It took some digging, but I was able to find the spots where I had to install the verifier. We start with a NullHostnameVerifier that returns true for everything:
public class NullHostnameVerifier implements HostnameVerifier { public boolean verify(String hostname, SSLSession session) { return true; } }
The org.springframework.ws.client.core.WebServiceTempate extends org.springframework.ws.client.support.WebServiceAccesor which uses a org.springframework.ws.client.support.WebServiceMessageSender. The WebServiceMessage sender for HTTPS is org.springframework.ws.transport.http.HttpsUrlConnectionMessageSender which is found in the spring-ws-support-1.5.9.jar. We need to create one of these and set the HostnameVerifier into it and pass it along to the WebServicesTemplate:
public void setWebServicesTempalate(WebServicesTemplate template) { HostnameVerifier verifier = new NullHostnameVerifier(); HttpsUrlConnectionMessageSender sender = new HttpsUrlConnectionMessageSender(); sender.setHostnameVerifier(verifier); template.setMessageSender(sender); this.template = template; }
The org.springframework.web.client.RestTemplate is setup differently. It uses a org.springframework.http.client.ClientHttpRequestFactory to handle the connections. Stepping thru the code, I found the RestTemplate using org.springframework.http.client.SimpleClientHttpRequestFactory which has a protected prepareConnection(…) method I could override and catch the HttpsURLConnection which I could set the verifier in. First we need our own ClientHttpRequestFactory:
public class MySimpleClientHttpRequestFactory extends SimpleClientHttpRequestFactory { private final HostnameVerifier verifier; public MySimpleClientHttpRequestFactory(HostnameVerifier verifier) { this.verifier = verifier; } @Override protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException { if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection) connection).setHostnameVerifier(verifier); } super.prepareConnection(connection, httpMethod); } }
Now we can use that as the request factory in our RestTemplate:
public void setRestTemplate(RestTemplate template) { HostnameVerifier verifier = new NullHostnameVerifier(); MySimpleClientHttpRequestFactory factory = new MySimpleClientHttpRequestFactory(verifier); template.setRequestFactory(factory); this.template = template; }
Once the NullHostnameVerifer is in place in the WebServiceTemplate and the RestTemplate, we will no longer see the error