java - CXF- HTTPS,无法连接到自签名服务器

标签 java ssl cxf

我目前正在使用 CXF 版本 3.1.10 开发 SOAP 服务器/客户端。 只要我不尝试使用 https,一切都已设置并且运行良好。 我没有使用任何 xml 文件/bean,除了那些可能被框架“在幕后”使用的文件/bean。

实际上我想保留它。

我正在使用自签名证书及其提取的 key ,以备不时之需。

服务器类

公共(public)类服务器扩展线程{

private static final Logger LOG         = Logger.getLogger(Server.class);

@WebService(name = "SoapService", serviceName = "SoapService", endpointInterface = "playground.mstahl.cxf_soap.SoapServiceDefinition")
private static final class ServerImpl implements SoapServiceDefinition {
    @Override
    public boolean handleStateDataRecipience(String user, String pass, String restri) throws Exception {
        return true;
    }
}

private final int       usedPort;
private final String    ksPath;
private final String    ksPass;
private final boolean   sslEnabled;

public Server(int port, boolean sslEnabled, String ksPath, String ksPass) {
    super("CXF-SOAP-Playground");
    setDaemon(true);
    usedPort = port;
    this.sslEnabled = sslEnabled;
    this.ksPath = ksPath;
    this.ksPass = ksPass;
    start();
}

@Override
public void run() {

    JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();

    sf.setAddress(String.format("http" + (sslEnabled ? "s" : "") + "://localhost:%d/signtest/", Integer.valueOf(usedPort))); // <- Yah, pretty ugly, but its just for testing purposes ;)
    sf.setServiceClass(ServerImpl.class);

    ServerImpl serviceBean = new ServerImpl();
    sf.setServiceBean(serviceBean);

    if (sslEnabled) {
        try {
            JettyHTTPServerEngineFactory factory = sf.getBus().getExtension(JettyHTTPServerEngineFactory.class);
            factory.setTLSServerParametersForPort(usedPort, getTLSServerParameters(ksPath, ksPass));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    org.apache.cxf.endpoint.Server server = sf.create();

    if (!server.isStarted()) {
        return;
    }


    LOG.debug("... done.");
    while (!IsInterrupted()) {
        try {
            Thread.sleep(100);
        } catch (Exception e) {
            //meh, just a test
        }
    }

    server.stop();
    server.destroy();
}

private final TLSServerParameters getTLSServerParameters(final String ksPath, final String ksPass) {
    TLSServerParameters tlsParams = null;
    try {
        tlsParams = new TLSServerParameters();

        File truststore = new File(ksPath);

        LOG.info("Try to load file " + truststore.getCanonicalPath());

        final KeyStore keyStore = KeyStore.getInstance("JKS");
        FileInputStream stream = new FileInputStream(truststore);
        final char[] keyStorePassphraseAsChar = ksPass.toCharArray();
        keyStore.load(stream, keyStorePassphraseAsChar);
        stream.close();

        final KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("PKIX");
        keyFactory.init(keyStore, keyStorePassphraseAsChar);
        final KeyManager[] km = keyFactory.getKeyManagers();
        tlsParams.setKeyManagers(km);

        truststore = new File(ksPath);
        stream = new FileInputStream(truststore);
        keyStore.load(stream, keyStorePassphraseAsChar);
        stream.close();

        final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX");
        trustFactory.init(keyStore);

        final TrustManager[] tm = trustFactory.getTrustManagers();
        tlsParams.setTrustManagers(tm);

        final SSLContext context = SSLContext.getDefault();
        final SSLSocketFactory sf = context.getSocketFactory();
        final List<String> cipherSuites = Arrays.asList(sf.getSupportedCipherSuites());
        LOG.info(String.format("Suppored cipher suites : %s", cipherSuites.toString()));

        final FiltersType filter = new FiltersType();
        final List<String> include = filter.getInclude();

        include.add(".*_EXPORT_.*");
        include.add(".*_EXPORT1024_.*");
        include.add(".*_WITH_DES_.*");
        include.add(".*_WITH_AES_.*");
        include.add(".*_WITH_NULL_.*");
        include.add(".*_RSA_WITH_AES_.*");
        include.add(".*_DH_anon_.*");

        tlsParams.setCipherSuitesFilter(filter);
        final ClientAuthentication ca = new ClientAuthentication();
        ca.setRequired(false);
        ca.setWant(false);
        tlsParams.setClientAuthentication(ca);

    } catch (final Exception e) {
        LOG.error("Security configuration failed with the following: " + e.getMessage() + " " + e.getCause());
        tlsParams = null;
    }

    return tlsParams;
}

我的服务器目前启动得很好。 (至少没有错误被抛出......) 我也可以访问给定的 soap 方法,只要我使用 http...

客户端类

public class Client {

private static final Logger             LOG = Logger.getLogger(Client.class);
private static SoapServiceDefinition    client;

public Client(String address, boolean sslEnabled, String ksFile, String ksPass) {

    // set keystore setting for plain httpclient
    if (sslEnabled) {
        LOG.debug("  ... collecting keystore file and passphrase due to enabled ssl.");
        System.setProperty("javax.net.ssl.keyStore", ksFile);
        System.setProperty("javax.net.ssl.trustStore", ksFile);
        System.setProperty("javax.net.ssl.keyStorePassword", ksPass);
        System.setProperty("javax.net.ssl.trustStorePassword", ksPass);
    }

    LOG.debug("  ... creating service factory.");
    final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
    factory.setServiceClass(SoapServiceDefinition.class);
    LOG.debug("  ... setting host address to '" + address + "'.");
    factory.setAddress(address);
    LOG.debug("  ... creating actual SOAP-client.");
    client = (SoapServiceDefinition) factory.create();

    final HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(client).getConduit();
    if (sslEnabled) {
        LOG.debug("  ... configuring SSL.");
        configureClientSideSSL(httpConduit, ksFile, ksPass);
        LOG.debug("  ... done.");
    }

    LOG.debug("  ... setting timeouts.");
    final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
    httpClientPolicy.setConnectionTimeout(0);
    httpClientPolicy.setReceiveTimeout(0);
    httpClientPolicy.setContentType("application/soap+xml");
    httpConduit.setClient(httpClientPolicy);

    retrieveAndStoreWSDL(address);

}

private void configureClientSideSSL(final HTTPConduit conduit, final String keyStorePath, final String trustpass) {
    try {
        final TLSClientParameters tlsParams = new TLSClientParameters();
        tlsParams.setDisableCNCheck(true);

        final KeyStore keyStore = KeyStore.getInstance("jceks");

        final File truststore = new File(keyStorePath);
        final FileInputStream stream = new FileInputStream(truststore);
        keyStore.load(stream, trustpass.toCharArray());
        final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX");
        trustFactory.init(keyStore);
        final TrustManager[] tm = trustFactory.getTrustManagers();
        tlsParams.setTrustManagers(tm);

        final KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("PKIX");
        keyFactory.init(keyStore, trustpass.toCharArray());
        final KeyManager[] km = keyFactory.getKeyManagers();
        tlsParams.setKeyManagers(km);

        final FiltersType filter = new FiltersType();
        final List<String> include = filter.getInclude();
        include.add(".*");
        include.add(".*_EXPORT_.*");
        include.add(".*_EXPORT1024_.*");
        include.add(".*_WITH_DES_.*");
        include.add(".*_WITH_AES_.*");
        include.add(".*_WITH_NULL_.*");
        include.add(".*_RSA_WITH_AES_.*");
        include.add(".*_DH_anon_.*");
        tlsParams.setCipherSuitesFilter(filter);

        conduit.setTlsClientParameters(tlsParams);

        stream.close();

    } catch (final Exception e) {
        System.out.println("Security configuration failed with the following: " + e.getCause());
    }
}

private void retrieveAndStoreWSDL(final String address) {

    LOG.info("  ... retrieving the WSDL-file."); 
    final HttpClient httpclient = new HttpClient();
    httpclient.getParams().setSoTimeout(0); // No timeout at all...in case of big wsdls

    final GetMethod get = new GetMethod(address);
    get.setQueryString("?wsdl");

    try {
        final int result = httpclient.executeMethod(get);
        final String str = IOUtils.toString(get.getResponseBodyAsStream(), "UTF-8");
        LOG.debug("    ... Response status code: " + result);
    } catch (final Throwable e) {
        LOG.debug("-", e);
        LOG.error(e.getClass().getSimpleName() + " occurred during WSDL-retrieval. Won't store current WSDL.");
    } finally {
        get.releaseConnection();
    }
}

public String helloReturn() throws Exception {
    return "haha:" + client.handleStateDataRecipience("", "", "");
}

客户端也在启动,但是,当客户端尝试检索 WSDL 和/或尝试执行它的任何方法时,我得到:

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
...

正如我之前提到的,只要我使用 http 而不是 https,一切都可以正常工作。

我不认为问题出在 keystore 上,因为我终于可以读取它们并通过使用例如获取它们的 key

private static void displayKeys(String ksForm, String alias, char[] ksPass, char[] kePass, String keystore) throws Exception {
    System.out
        .println("---------------------------------------------------------------------------------------------------------------------------");
    KeyStore keyStore = KeyStore.getInstance(ksForm);
    keyStore.load(new FileInputStream(keystore), ksPass);

    Key key = keyStore.getKey(alias, kePass);

    if (key instanceof PrivateKey) {
        System.out.println("Get private key : ");
        System.out.println(key.toString());

        java.security.cert.Certificate[] certs = keyStore.getCertificateChain(alias);
        System.out.println("Certificate chain length : " + certs.length);
        for (Certificate cert : certs) {
            System.out.println(cert.toString());
        }
    } else {
        System.out.println("Get public key : ");
        System.out.println(key.toString());
    }
    System.out
        .println("---------------------------------------------------------------------------------------------------------------------------");
}


Caused by: java.io.EOFException: SSL peer shut down incorrectly

在此先致谢并致以亲切的问候。

最佳答案

所以,我终于弄明白了。 实际上手头有几个问题

  • 创建的 keystore 本身很好,提取的(供客户端使用的)证书不是
  • 在服务器和客户端加载 keystore truststore 是一个巨大的错误,特别是因为我对两者使用了相同的存储/证书(为此我认为 WSS4J 拦截器和 CallBackHandlers 是必要的)
  • 在几次试错期间,我似乎也混淆了输入和存储密码。

下面我将为您提供我用来获得完整运行示例的所有类的代码。

key 和证书生成

由于我在使用 SunAPI 及其证书创建代码示例时总是遇到问题,因此我决定改用 BouncyCaSTLe。
尽管我之前决定不使用第 3 方工具,但由于我仅将其用于创建 keystore /证书这一事实,我改变了主意。
您即将看到的类(class)是“Maarten Bodewes”对这个问题的回答的略微修改版本:
How to store and reuse keypair in Java?
该类非常简单,因此没有添加任何方法注释...

package playground.TEST.cxf_soap;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableEntryException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.Date;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

public class BCCertUtils {

    public static KeyPair generateKeyPair(int keySize, String keyAlgo, String secureAlgo) throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlgo != null && !keyAlgo.trim().isEmpty() ? keyAlgo : "RSA");
        keyGen.initialize(keySize, secureAlgo != null && !secureAlgo.trim().isEmpty() ? SecureRandom.getInstance(secureAlgo) : new SecureRandom());
        KeyPair pair = keyGen.generateKeyPair();
        return pair;
    }

    public static Certificate generateSelfSignedCertificate(KeyPair keyPair, String dn, String sigAlg, Date endDate)
            throws OperatorCreationException, CertificateException {

        // Setting bouncy castle provider to be able to create certs at all... 
        Provider bcProvider = new BouncyCastleProvider();
        Security.addProvider(bcProvider);
        X500Name dnName = new X500Name(dn);

        // Using the current timestamp as the certificate serial number
        BigInteger certSerialNum = new BigInteger(String.valueOf(System.currentTimeMillis()));

        // Setting start date
        Date startDate = Calendar.getInstance().getTime();

        // Use appropriate signature algorithm based on your keyPair algorithm.
        String sigAlgorithm = sigAlg == null || sigAlg.trim().isEmpty() ? "SHA256WithRSA" : sigAlg;

        SubjectPublicKeyInfo certPubKey = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());

        X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(dnName, certSerialNum, startDate, endDate, dnName, certPubKey);

        ContentSigner contentSigner = new JcaContentSignerBuilder(sigAlgorithm).setProvider(bcProvider).build(keyPair.getPrivate());

        X509CertificateHolder certificateHolder = certBuilder.build(contentSigner);

        return new JcaX509CertificateConverter().getCertificate(certificateHolder);

    }

    public static void storeToPKCS12File(String alias, Certificate selfCert, String filename, char[] ksPass, char[] kePass, PrivateKey privKey)
            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, OperatorCreationException {

        KeyStore p12Store = createP12Store(alias, selfCert, privKey, kePass);
        try (FileOutputStream fos = new FileOutputStream(filename)) {
            p12Store.store(fos, ksPass);
        }
    }

    public static byte[] storeToPKCS12ByteArray(String alias, Certificate selfCert, char[] ksPass, char[] kePass, PrivateKey privKey)
            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, OperatorCreationException {

        KeyStore p12Store = createP12Store(alias, selfCert, privKey, kePass);
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            p12Store.store(bos, ksPass);
            return bos.toByteArray();
        }

    }

    private static KeyStore createP12Store(String alias, Certificate selfCert, PrivateKey privKey, char[] kePass)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {

        KeyStore p12KeyStore = KeyStore.getInstance("PKCS12");
        p12KeyStore.load(null, null);

        KeyStore.Entry entry = new PrivateKeyEntry(privKey, new Certificate[] { selfCert });
        KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(kePass);

        p12KeyStore.setEntry(alias, entry, param);

        return p12KeyStore;
    }

    public static boolean moduliMatch(PublicKey originPubKey, PrivateKey certPrivKey) {
        return ((RSAPublicKey) originPubKey).getModulus().equals(((RSAPrivateKey) certPrivKey).getModulus());
    }

    public static KeyPair loadKeysFromPKCS12File(String alias, String filename, char[] storePass, char[] entryPass) throws KeyStoreException,
            NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {

        KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream fis = new FileInputStream(filename);) {
            pkcs12KeyStore.load(fis, storePass);
        }

        return loadKeyPair(pkcs12KeyStore, alias, entryPass);
    }

    public static KeyPair loadKeysFromPKCS12ByteArray(String alias, byte[] storeBytes, char[] storePass, char[] entryPass) throws KeyStoreException,
            NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {

        KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
        try (ByteArrayInputStream bis = new ByteArrayInputStream(storeBytes);) {
            pkcs12KeyStore.load(bis, storePass);
        }

        return loadKeyPair(pkcs12KeyStore, alias, entryPass);
    }

    private static KeyPair loadKeyPair(KeyStore ks, String alias, char[] entryPass)
            throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException {
        KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(entryPass);
        Entry entry = ks.getEntry(alias, param);
        if (!(entry instanceof PrivateKeyEntry)) {
            throw new KeyStoreException("That's not a private key!");
        }
        PrivateKeyEntry privKeyEntry = (PrivateKeyEntry) entry;
        PublicKey publicKey = privKeyEntry.getCertificate().getPublicKey();
        PrivateKey privateKey = privKeyEntry.getPrivateKey();
        return new KeyPair(publicKey, privateKey);
    }

    public static Certificate loadCertFromPKCS12File(String alias, String filename, char[] storePass, char[] entryPass) throws KeyStoreException,
            NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {

        KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream fis = new FileInputStream(filename);) {
            pkcs12KeyStore.load(fis, storePass);
        }
        return loadCert(pkcs12KeyStore, alias, entryPass);
    }

    public static Certificate loadCertFromPKCS12ByteArray(String alias, byte[] storeBytes, char[] storePass, char[] entryPass)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException,
            UnrecoverableEntryException {

        KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
        try (ByteArrayInputStream bis = new ByteArrayInputStream(storeBytes);) {
            pkcs12KeyStore.load(bis, storePass);
        }
        return loadCert(pkcs12KeyStore, alias, entryPass);
    }

    private static Certificate loadCert(KeyStore ks, String alias, char[] entryPass)
            throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException {

        KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(entryPass);
        Entry entry = ks.getEntry(alias, param);
        if (!(entry instanceof PrivateKeyEntry)) {
            throw new KeyStoreException("That's not a private key!");
        }
        PrivateKeyEntry privKeyEntry = (PrivateKeyEntry) entry;
        return privKeyEntry.getCertificate();
    }

    public static void storeToPEMFile(Certificate pubCert, String certPath) throws IOException {
        JcaPEMWriter pw = new JcaPEMWriter(new FileWriter(certPath));
        pw.writeObject(pubCert);
        pw.flush();
        pw.close();

    }

    public static byte[] storeToPEMByteArray(Certificate pubCert) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(baos));
        JcaPEMWriter pw = new JcaPEMWriter(writer);
        pw.writeObject(pubCert);
        pw.flush();
        pw.close();
        return baos.toByteArray();

    }

}


初级类

这是我实际生成 key 并启动服务器和客户端以及使用客户端方法的代码。

package playground.test.cxf_soap;

import java.security.KeyPair;
import java.security.cert.Certificate;
import java.util.Calendar;

public class Starter {
    public static void main(String[] args) {

        try {

            boolean enableSSL = true;
            char[] entryPass = "entryPass".toCharArray();
            char[] storePass = "storePass".toCharArray();

            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.YEAR, 100);

            // Server Store and Client cert.
            KeyPair srvKeyPair = BCCertUtils.generateKeyPair(2048, "RSA", "SHA1PRNG");
            Certificate srvPrivCert = BCCertUtils.generateSelfSignedCertificate(srvKeyPair, "CN=Test", "SHA256WithRSA", calendar.getTime());
            byte[] srvStoreBytes = BCCertUtils.storeToPKCS12ByteArray("alias", srvPrivCert, storePass, entryPass, srvKeyPair.getPrivate());
            KeyPair SvrCertKeys = BCCertUtils.loadKeysFromPKCS12ByteArray("alias", srvStoreBytes, storePass, entryPass);
            if (!BCCertUtils.moduliMatch(srvKeyPair.getPublic(), SvrCertKeys.getPrivate())) {
                System.err.println("ARRGL");
                return;
            }
            Certificate clientCert = BCCertUtils.loadCertFromPKCS12ByteArray("alias", srvStoreBytes, storePass, entryPass);
            byte[] clientCertBytes = BCCertUtils.storeToPEMByteArray(clientCert);

            Server server = new Server(443, enableSSL, srvStoreBytes, storePass, entryPass);
            while (!server.isRunning()) {
                Thread.sleep(10);
            }

            Client client = new Client("https://localhost:" + 443 + "/signtest/", enableSSL, clientCertBytes);

            System.out.println("Hello SOAP-Server :)");
            System.out.println("  -> " + client.helloReturn("Stahler"));

            System.out.println("Could you tell me if it is working?");
            System.out.println("  -> " + client.isItWorking());

            System.out.println("Awww finally, thank you server and goodbye.");
            System.out.println("  -> " + client.gbyeReturn("Stahler"));
            System.exit(0);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }  
}


服务器类

接下来我将向您展示我的服务器类,我在其中导入之前创建的 PKCS12 存储并调整 TLS 设置以与客户端一起工作。 包 playground.mstahl.cxf_soap;

 import java.io.ByteArrayInputStream;
 import java.security.KeyStore;
 import java.util.Arrays;
 import java.util.List;

 import javax.jws.WebService;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;

 import org.apache.cxf.configuration.jsse.TLSServerParameters;
 import org.apache.cxf.configuration.security.ClientAuthentication;
 import org.apache.cxf.configuration.security.FiltersType;
 import org.apache.cxf.endpoint.Endpoint;
 import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
 import org.apache.cxf.transport.http_jetty.JettyHTTPServerEngineFactory;

 public class Server extends Thread {

    private boolean             isRunning   = false;

    @WebService(name = "SoapService", serviceName = "SoapService", endpointInterface = "playground.mstahl.cxf_soap.SoapServiceDefinition")
    private static final class ServerImpl implements SoapServiceDefinition {

        @Override
        public String sayHelloToMe(String caller) throws Exception {
            return "oh Hello " + caller + ".";
        }

        @Override
        public String askFunctionality() throws Exception {
            return "Well, as I am answering I guess its working...duh";
        }

        @Override
        public String sayGoodbyeToMe(String caller) throws Exception {
            return "Goodbye doucheb...i mean..." + caller + ".";
        }

    }

    private final int       usedPort;
    private final byte[]    storeBytes;
    private final char[]    storePass;
    private final char[]    entryPass;
    private final boolean   sslEnabled;

    public Server(int port, boolean sslEnabled, byte[] storeBytes, char[] storePass, char[] entryPass) {
        super("CXF-SOAP-Playground");
        setDaemon(true);
        usedPort = port;
        this.sslEnabled = sslEnabled;
        this.storeBytes = storeBytes;
        this.storePass = storePass;
        this.entryPass = entryPass;
        start();
    }

    @Override
    public void run() {

        System.out.println("  ... creating factory.");
        JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();

        System.out.println("  ... setting address and implementing service.");
        sf.setAddress(String.format("http" + (sslEnabled ? "s" : "") + "://localhost:%d/signtest/", Integer.valueOf(usedPort)));
        sf.setServiceClass(ServerImpl.class);

        System.out.println("  ... setting up service bean.");
        ServerImpl serviceBean = new ServerImpl();
        sf.setServiceBean(serviceBean);

        if (sslEnabled) {

            try {
                JettyHTTPServerEngineFactory factory = sf.getBus().getExtension(JettyHTTPServerEngineFactory.class);
                factory.setTLSServerParametersForPort(usedPort, getTLSServerParameters());
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        System.out.println("  ... starting actual SOAP-server.");
        org.apache.cxf.endpoint.Server server = sf.create();

        Endpoint endpoint = server.getEndpoint();
        String endpointAddr = endpoint.getEndpointInfo().getAddress();

        System.out.println("Server started at " + endpointAddr);

        if (!server.isStarted()) {
            return;
        }

        isRunning = true;
        System.out.println("... done.");
        while (!isInterrupted()) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {
            }
        }

        System.out.println("... stopping actual SOAP-server.");
        server.stop();
        System.out.println("... destroying its remnants.");
        server.destroy();
    }

    public boolean isRunning() {
        return isRunning;
    }

    private final TLSServerParameters getTLSServerParameters() {
        TLSServerParameters tlsParams = null;
        try {

            // 1 - Load key store
            KeyStore localKeyStore = KeyStore.getInstance("PKCS12");
            localKeyStore.load(new ByteArrayInputStream(storeBytes), storePass);

            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(localKeyStore, entryPass);

            // 2 - Add the new keyManager to the tls settings. 
            tlsParams = new TLSServerParameters();
            tlsParams.setKeyManagers(kmf.getKeyManagers());

            // 3 - Adjust cipher suite filters
            final List<String> cipherSuites = Arrays.asList(SSLContext.getDefault().getSocketFactory().getSupportedCipherSuites());
            System.out.println(String.format("Suppored cipher suites : %s", cipherSuites.toString()));

            final FiltersType filter = new FiltersType();
            final List<String> include = filter.getInclude();

            include.add(".*");
            include.add(".*_EXPORT1024_.*");
            include.add(".*_WITH_DES_.*");
            include.add(".*_WITH_AES_.*");
            include.add(".*_WITH_NULL_.*");
            include.add(".*_RSA_WITH_AES_.*");
            include.add(".*_DH_anon_.*");

            tlsParams.setCipherSuitesFilter(filter);

            // 4 - Disable client authentication
            final ClientAuthentication ca = new ClientAuthentication();
            ca.setRequired(false);
            ca.setWant(false);
            tlsParams.setClientAuthentication(ca);

        } catch (final Exception e) {
            e.printStackTrace();
            System.err.println("Security configuration failed with the following: " + e.getMessage() + " " + e.getCause());
            tlsParams = null;
        }

        return tlsParams;
    }

 }


客户端类

最后但同样重要的是,我在一个小型客户端类中导入了之前从服务器 keystore 导出的证书。 包 playground.mstahl.cxf_soap;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.io.IOUtils;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.configuration.security.FiltersType;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.System.out.println4j.System.out.printlnger;

public class Client {

    private static SoapServiceDefinition    client;

    public Client(String address, boolean sslEnabled, byte[] remoteCertBytes) {

        System.out.println("  ... creating service factory.");
        final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(SoapServiceDefinition.class);
        System.out.println("  ... setting host address to '" + address + "'.");
        factory.setAddress(address);
        System.out.println("  ... creating actual SOAP-client.");
        client = (SoapServiceDefinition) factory.create();

        final HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(client).getConduit();
        if (sslEnabled) {
            System.out.println("  ... configuring SSL.");
            configureClientSideSSL(httpConduit, remoteCertBytes);
            System.out.println("  ... done.");
        }

        System.out.println("  ... setting timeouts.");
        final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
        httpClientPolicy.setConnectionTimeout(0);
        httpClientPolicy.setReceiveTimeout(0);
        httpClientPolicy.setContentType("application/soap+xml");
        httpConduit.setClient(httpClientPolicy);
        try {
            retrieveAndStoreWSDL(sslEnabled, address);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void configureClientSideSSL(final HTTPConduit conduit, byte[] remoteCertBytes) {

        TLSClientParameters tlsParams = null;
        try {

            // 1 - Load the remote certificate
            ByteArrayInputStream bis = new ByteArrayInputStream(remoteCertBytes);
            X509Certificate remoteCert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(new BufferedInputStream(bis));

            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(null, null);
            ks.setCertificateEntry(Integer.toString(1), remoteCert);

            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(ks);

            // 2 - Add the new trustmanager to the tls settings. 
            tlsParams = new TLSClientParameters();
            tlsParams.setTrustManagers(tmf.getTrustManagers());

            // 3 - Disable CN check
            tlsParams.setDisableCNCheck(true);

            // 4 - Set default SSL-context (necessary for e.g. the wsdl retrieval)
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);
            SSLContext.setDefault(context);

            final FiltersType filter = new FiltersType();
            final List<String> include = filter.getInclude();
            include.add(".*");
            include.add(".*_EXPORT_.*");
            include.add(".*_EXPORT1024_.*");
            include.add(".*_WITH_DES_.*");
            include.add(".*_WITH_AES_.*");
            include.add(".*_WITH_NULL_.*");
            include.add(".*_RSA_WITH_AES_.*");
            include.add(".*_DH_anon_.*");
            tlsParams.setCipherSuitesFilter(filter);

            conduit.setTlsClientParameters(tlsParams);

        } catch (final Exception e) {
            e.printStackTrace();
            System.out.println("Security configuration failed with the following: " + e.getCause());
        }
    }

    private void retrieveAndStoreWSDL(boolean sslEnabled, final String address) throws Exception {

        System.out.println("  ... retrieving the WSDL-file."); // TODO ssl enabled check (Necessary if we do this beforehand?)
        URL wsdlUrl = new URL(address + "?wsdl");

        URLConnection connection = wsdlUrl.openConnection();
        HttpsURLConnection conn = (HttpsURLConnection) connection;
        if (sslEnabled) {
            conn.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
        }
        conn.setRequestMethod("GET");
        conn.connect();

        String wsdl = IOUtils.toString(conn.getInputStream(), Charset.defaultCharset());
        System.err.println(wsdl);
        conn.disconnect();

    }

    public String helloReturn(String caller) throws Exception {
        return client.sayHelloToMe(caller);
    }

    public String isItWorking() throws Exception {
        return client.askFunctionality();
    }

    public String gbyeReturn(String caller) throws Exception {
        return client.sayGoodbyeToMe(caller);
    }

}

感谢所有阅读我的问题并想到可能解决方案的人。 希望这可以帮助其他人。 亲切的问候

关于java - CXF- HTTPS,无法连接到自签名服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44543969/

相关文章:

web-services - 如何在 JBoss AS 7 中禁用扫描@WebService 注释?

java - JNI - C++/Java 中的监听器 - 是否可以在 C++ 中实例化 Java 对象并将它们用作参数

java - 放心 : Making a GET request with a parameters map

java - 用空格作为分隔符将它们分开,但<>中的空格在Java中应该被忽略

linux - 服务器身份验证失败(SVN/Jenkins)Maven 发布

java - Apache CXF 设置上传大小

java - response.sendRedirect 到来自 Chrome 的文件 URL

c# - 在 TLS : The remote server return an error : 234 AUTH TLS OK 上使用 FtpWebRequest 的问题

ssl - Mosquitto TLS,适用于 MQTTfx 但不适用于 mosquitto_pub(tlsv1 警报未知 ca)

java - getSupportedCipherSuites 与 getDefaultCipherSuites Apache CXF