Apache CXF wsdl descarga a través de SSL / TLS

Tengo un servicio cxf corriendo en

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

con certificado de cliente requerido. El WSDL no es importante aquí.

Soy capaz de invocar el servicio cuando elimino el certificado de cliente o el requisito de https.

Las clases de servicio y cliente se generaron con la utilidad cxf wsdl2java.

Aquí está 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);
    }

}

Aquí está mi cliente sin el requisito de certificado de cliente: (que funciona bien)

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();
        }
    }
}

Y aquí está mi cliente enviar su certificado:

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;
    }

}

La configuración TLS tanto del cliente como del servidor fueron verificadas y están bien. Pero cuando ejecuto el programa me sale esto:

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

Puedo ver que el problema está ocurriendo antes de que se realice mi configuración https, cuando cxf intenta descargar el wsdl.

Hice una investigación sobre cómo hacer que cxf use esa configuración https para descargar el wsdl. Me toma mucho tiempo, pero no puedo encontrar la respuesta ahí fuera.

Entonces mi pregunta es: ¿cómo hacer que cxf use la configuración https para descargar el wsdl?

Por favor, ya tengo la respuesta y tengo la intención de ponerla aquí. Por lo tanto, si no tiene una buena respuesta, o mejor la respuesta, no publique una.

Respuestas a la pregunta(4)

Su respuesta a la pregunta