Apache CXF wsdl download via SSL / TLS

I have a cxf service running on

https://localhost:8443/services/MyService?wsdl 

with the required client certificate. WSDL is not important here.

I can call the service when deleting a client certificate or https request.

Service and client classes were generated using the cxf wsdl2java utility.

Here is MyService.class:

 package com.mycompany; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.namespace.QName; import javax.xml.ws.Service; import javax.xml.ws.WebEndpoint; import javax.xml.ws.WebServiceClient; import javax.xml.ws.WebServiceFeature; /** * This class was generated by Apache CXF 2.7.3 2013-03-29T13:59:37.423-03:00 Generated source version: 2.7.3 */ @WebServiceClient(name = "MyService", wsdlLocation = "myservice.wsdl", targetNamespace = "http://server/schemas/services") public class MyService extends Service { public final static URL WSDL_LOCATION; public final static QName SERVICE = new QName("http://server/schemas/services", "MyService"); public final static QName MyServicePort = new QName("http://server/schemas/services", "MyServicePort"); static { URL url = MyService.class.getResource("myservice.wsdl"); if (url == null) { Logger.getLogger(MyService.class.getName()).log(Level.INFO, "Can not initialize the default wsdl from {0}", "myservice.wsdl"); } WSDL_LOCATION = url; } public MyService(URL wsdlLocation) { super(wsdlLocation, SERVICE); } public MyService(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } public MyService() { super(WSDL_LOCATION, SERVICE); } /** * * @return returns EncaminharMensagemPortType */ @WebEndpoint(name = "MyServicePort") public MyServicePortType getMyServicePort() { return super.getPort(MyServicePort, MyServicePortType.class); } /** * * @param features * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the * <code>features</code> parameter will have their default values. * @return returns EncaminharMensagemPortType */ @WebEndpoint(name = "MyServicePort") public MyServicePortType getMyServicePort(WebServiceFeature... features) { return super.getPort(MyServicePort, MyServicePortType.class, features); } } 

Here is my client without a client certificate requirement: (this works fine)

 package com.mycompany; import java.net.URL; import javax.xml.namespace.QName; import com.mycompany.IdHolder; import com.mycompany.MyDataObject; public class CxfClientSslTest { public static void main(String[] args) { try { QName SERVICE_NAME = new QName("http://server/schemas/services", "MyService"); URL wsdlURL = new URL("https://localhost:8443/services/MyService?wsdl"); MyService ss = new MyService(wsdlURL, SERVICE_NAME); MyServicePortType port = ss.getMyServicePort(); IdHolder mensagem = new IdHolder(); mensagem.setId(1L); MyDataObject dataObject = port.getById(mensagem); System.out.println("Id: " + dataObject.getId()); } catch (Exception e) { e.printStackTrace(); } } } 

And so my client will send their certificate:

 package com.mycompany; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.xml.namespace.QName; import org.apache.cxf.configuration.jsse.TLSClientParameters; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.transport.http.HTTPConduit; public class CxfClientSslTest { public static void main(String[] args) { try { QName SERVICE_NAME = new QName("http://server/schemas/services", "MyService"); URL wsdlURL = new URL("https://localhost:8443/services/MyService?wsdl"); MyService ss = new MyService(wsdlURL, SERVICE_NAME); MyServicePortType port = ss.getMyServicePort(); tslIt(port); IdHolder mensagem = new IdHolder(); mensagem.setId(1L); MyDataObject dataObject = port.getById(mensagem); System.out.println("Id: " + dataObject.getId()); } catch (Exception e) { e.printStackTrace(); } } public static void tslIt(MyServicePortType port) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException { Client client = ClientProxy.getClient(port); HTTPConduit http = (HTTPConduit) client.getConduit(); TLSClientParameters tlsClientParameters = http.getTlsClientParameters(); KeyStore keyStore = getKeyStore(); KeyStore trustStore = getTrustStore(); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, "123456".toCharArray()); KeyManager[] keyMgrs = keyManagerFactory.getKeyManagers(); tlsClientParameters.setKeyManagers(keyMgrs); trustManagerFactory.init(trustStore); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); tlsClientParameters.setTrustManagers(trustManagers); tlsClientParameters.setDisableCNCheck(true); } public static KeyStore getKeyStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { URL keyStoreUrl = CxfClientSslTest.class.getResource("/certs/client.jks"); File keystoreFile = new File(keyStoreUrl.getPath()); if (!keystoreFile.exists()) { throw new RuntimeException("keystore doesn't exists: " + keystoreFile.getAbsolutePath()); } KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream keystoreInput = new FileInputStream(keystoreFile.getAbsolutePath()); keystore.load(keystoreInput, "changeit".toCharArray()); keystoreInput.close(); return keystore; } public static KeyStore getTrustStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { URL trustStoreUrl = CxfClientSslTest.class.getResource("/certs/client-trust.jks"); File trustStoreFile = new File(trustStoreUrl.getPath()); if (!trustStoreFile.exists()) { throw new RuntimeException("truststore doesn't exists: " + trustStoreFile.getAbsolutePath()); } KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream trustStoreInput = new FileInputStream(trustStoreFile.getAbsolutePath()); trustStore.load(trustStoreInput, "changeit".toCharArray()); trustStoreInput.close(); return trustStore; } } 

The TLS configuration from both the client and the server has been verified and is in order. But when I run the program, I get the following:

 Information: Can not initialize the default wsdl from myservice.wsdl javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException: Failed to create service. at org.apache.cxf.jaxws.ServiceImpl.<init>(ServiceImpl.java:149) at org.apache.cxf.jaxws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:98) at javax.xml.ws.Service.<init>(Service.java:77) at com.mycompany.MyService.<init>(MyService.java:36) at com.mycompany.CxfClientSslTest.main(CxfClientSslTest.java:32) Caused by: org.apache.cxf.service.factory.ServiceConstructionException: Failed to create service. at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:100) at org.apache.cxf.jaxws.ServiceImpl.initializePorts(ServiceImpl.java:199) at org.apache.cxf.jaxws.ServiceImpl.<init>(ServiceImpl.java:147) ... 4 more Caused by: javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR: Problem parsing 'https://localhost:8443/services/MyService?wsdl'.: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found at com.ibm.wsdl.xml.WSDLReaderImpl.getDocument(Unknown Source) at com.ibm.wsdl.xml.WSDLReaderImpl.readWSDL(Unknown Source) at com.ibm.wsdl.xml.WSDLReaderImpl.readWSDL(Unknown Source) at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:262) at org.apache.cxf.wsdl11.WSDLManagerImpl.getDefinition(WSDLManagerImpl.java:205) at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:98) ... 6 more Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1868) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1337) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:154) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868) at sun.security.ssl.Handshaker.process_record(Handshaker.java:804) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:998) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1294) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1321) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1305) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:653) at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:189) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:799) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123) at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:240) at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:300) ... 12 more Caused by: java.security.cert.CertificateException: No name matching localhost found at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:208) at sun.security.util.HostnameChecker.match(HostnameChecker.java:93) at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:347) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:203) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1319) ... 30 more 

I see that the problem occurs before my https configuration is done when cxf tries to load wsdl.

I did research on how to get cxf to use this https configuration to download wsdl. I need a lot of time, but I can not find the answer.

So my question is: how to get cxf to use the https configuration to load wsdl?

Please, I already have an answer, and I intend to put it here. So, if you do not have a good answer or a better answer, please do not post it.

+4
source share
4 answers

After much research on the Internet without success, I decided it was time to debug the cxf API. This is one of the points of open source, right?

So, I found out that cxf does not load wsdl directly. He delegates this to wsdl4j through a call

 javax.wsdl.xml.WSDLReader.readWSDL(javax.wsdl.xml.WSDLLocator) 

which causes

 javax.wsdl.xml.WSDLLocator.getBaseInputSource() 

which causes

 org.apache.cxf.wsdl11.ResourceManagerWSDLLocator.getInputSource(String, String) 

since ResourceManagerWSDLLocator was the WSDLLocator of the first method call.

The first line is ResourceManagerWSDLLocator.getInputSource:

 InputStream ins = bus.getExtension(ResourceManager.class).getResourceAsStream(importLocation); 

Now that the ResourceManager is an extension of xcf Bus, and you can add more ResourceResolver to it, and the DefaultResourceManager (implements the ResourceManager) will cycle through all the registered transformers and will use the first one that allows a non-zero value, you just need to add the ResourceResolver to the ResourceManager.

My final and working client application:

 package com.mycompany; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.xml.namespace.QName; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; import org.apache.cxf.configuration.jsse.TLSClientParameters; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.resource.ResourceManager; import org.apache.cxf.resource.ResourceResolver; import org.apache.cxf.transport.http.HTTPConduit; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.BasicClientConnectionManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; public class CxfClientSslTest { public static void main(String[] args) { try { Bus bus = BusFactory.getThreadDefaultBus(); ResourceManager extension = bus.getExtension(ResourceManager.class); extension.addResourceResolver(new ResourceResolver() { @Override public <T> T resolve(String resourceName, Class<T> resourceType) { System.out.println("resourceName: " + resourceName + " - resourceType: " + resourceType); return null; } @Override public InputStream getAsStream(String name) { try { if (!name.startsWith("https")) { return null; } SSLSocketFactory sslSocketFactory = SslUtil.getSslSocketFactory(); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("https", 8443, sslSocketFactory)); final HttpParams httpParams = new BasicHttpParams(); DefaultHttpClient httpClient = new DefaultHttpClient(new BasicClientConnectionManager(schemeRegistry), httpParams); HttpGet get = new HttpGet(name); HttpResponse response = httpClient.execute(get); return response.getEntity().getContent(); } catch (Exception e) { return null; } } }); QName SERVICE_NAME = new QName("http://server/schemas/services", "MyService"); URL wsdlURL = new URL("https://localhost:8443/services/MyService?wsdl"); MyService ss = new MyService(wsdlURL, SERVICE_NAME); MyServicePortType port = ss.getMyServicePort(); tslIt(port); IdHolder mensagem = new IdHolder(); mensagem.setId(1L); MyDataObject dataObject = port.getById(mensagem); System.out.println("Id: " + dataObject.getId()); } catch (Exception e) { e.printStackTrace(); } } public static void tslIt(MyServicePortType port) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException { Client client = ClientProxy.getClient(port); HTTPConduit http = (HTTPConduit) client.getConduit(); TLSClientParameters tlsClientParameters = http.getTlsClientParameters(); KeyStore keyStore = getKeyStore(); KeyStore trustStore = getTrustStore(); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, "123456".toCharArray()); KeyManager[] keyMgrs = keyManagerFactory.getKeyManagers(); tlsClientParameters.setKeyManagers(keyMgrs); trustManagerFactory.init(trustStore); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); tlsClientParameters.setTrustManagers(trustManagers); tlsClientParameters.setDisableCNCheck(true); } public static KeyStore getKeyStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { URL keyStoreUrl = CxfClientSslTest.class.getResource("/certs/client.jks"); File keystoreFile = new File(keyStoreUrl.getPath()); if (!keystoreFile.exists()) { throw new RuntimeException("keystore doesn't exists: " + keystoreFile.getAbsolutePath()); } KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream keystoreInput = new FileInputStream(keystoreFile.getAbsolutePath()); keystore.load(keystoreInput, "changeit".toCharArray()); keystoreInput.close(); return keystore; } public static KeyStore getTrustStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { URL trustStoreUrl = CxfClientSslTest.class.getResource("/certs/client-trust.jks"); File trustStoreFile = new File(trustStoreUrl.getPath()); if (!trustStoreFile.exists()) { throw new RuntimeException("truststore doesn't exists: " + trustStoreFile.getAbsolutePath()); } KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream trustStoreInput = new FileInputStream(trustStoreFile.getAbsolutePath()); trustStore.load(trustStoreInput, "changeit".toCharArray()); trustStoreInput.close(); return trustStore; } } 
+8
source
 tlsClientParameters.setUseHttpsURLConnectionDefaultSslSocketFactory(false); 

To disable the standard SslSocketFactory, a string is required by default, which will ignore the keyStore and trustStore configured in tlsClientParamters.

0
source

I think the standard way in apache cxf is to configure the http conduit in your cxf.xml, referencing your jks keystore:

 <http:conduit id="{Namespace}PortName.http-conduit"> <http:tlsClientParameters> ... <sec:trustManagers> <sec:keyStore type="JKS" password="StorePass" file="certs/truststore.jks"/> </sec:trustManagers> ... </http:tlsClientParameters> </http:conduit> 

More information here: Configuring SSL Support

0
source

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: could not find a name matching the local host

The above exception occurs when you create your self-signed certificate with your name. To eliminate this exception, you need to add "localhost" in the next step

 What is your first and last name? [Unknown]: localhost 
-1
source

Source: https://habr.com/ru/post/943700/


All Articles