java - 设置多个 SSL 套接字工厂

标签 java ssl rmi google-cloud-messaging

我有一段 Java 代码(实际上是一个 servlet)需要与以下对象进行安全通信:

  1. 另一个 java 进程,通过 RMI,进行安全的远程方法调用和
  2. Google GCM 服务器,用于向移动设备发送通知。

这是一段安全绑定(bind)到远程对象的代码:

    // let's set some system properties needed for RMI on SSL
    Properties sysProps = System.getProperties();
    sysProps.setProperty("javax.net.ssl.keyStore", ...);
    sysProps.setProperty("javax.net.ssl.keyStorePassword", ...);
    sysProps.setProperty("javax.net.ssl.trustStore", ...);
    sysProps.setProperty("javax.net.ssl.trustStorePassword", ...);

    try {
        String registryHost = ...;
        int registryPort = ...;

        Registry registry = LocateRegistry.getRegistry(registryHost, registryPort, new SslRMIClientSocketFactory());
        MyRemoteObject obj = (MyRemoteObject) registry.lookup(...);
    } catch (Exception e) {
        log.error("RMI Exception",e);
    } 

然后,为了连接到 Google GCM 服务器,我拥有 Google 提供的唯一代码以及我阅读过的所有教程:

    config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
    config.setSecurityMode(SecurityMode.enabled);
    config.setReconnectionAllowed(true);
    config.setRosterLoadedAtLogin(false);
    config.setSendPresence(false);
    config.setSocketFactory(SSLSocketFactory.getDefault());

    // NOTE: Set to true to launch a window with information about packets
    // sent and received
    config.setDebuggerEnabled(true);

    // -Dsmack.debugEnabled=true
    XMPPConnection.DEBUG_ENABLED = false;

    connection = new XMPPConnection(config);
    connection.connect();

我可以让其中一段代码同时工作,但我无法同时建立两个安全连接。我可以使用默认的 SSLSocketFactory 或设置 RMI SSL 套接字工厂,但不能同时使用两者。如果我先连接到 RMI 服务器,当我尝试连接到 Google GCM 服务器时会收到以下错误:

2014-09-08 16:14:05,172 ERROR [pool-4-thread-1] (GcmManager.java:109) - Problems connecting with Google XMPP servers
Connection failed. No response from server.: 
at org.jivesoftware.smack.PacketReader.startup(PacketReader.java:121)
at org.jivesoftware.smack.XMPPConnection.initConnection(XMPPConnection.java:636)
at org.jivesoftware.smack.XMPPConnection.connectUsingConfiguration(XMPPConnection.java:596)
at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:1010)
at com.tigratelecom.server.callback.web.notification.GcmManager.connect(GcmManager.java:171)
at com.tigratelecom.server.callback.web.notification.GcmManager.sendNotification(GcmManager.java:107)
at com.tigratelecom.server.callback.web.notification.NotificationSender.sendNotifications(NotificationSender.java:24)
at com.tigratelecom.server.callback.web.servlet.CallbackServlet$1.run(CallbackServlet.java:107)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:351)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)

然而,如果我先连接到 Google 服务器,一切顺利,直到我尝试连接到 RMI 服务器,但失败并出现以下错误:

java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: 
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:304)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:340)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at ...

你能给我指出正确的方向吗?

谢谢

最佳答案

我继续摆弄这个问题,直到我找到了一些东西。我在假设连接到 Google GCM 服务器(来自 Smack 库)的代码的情况下工作,因为它使用默认的 SSLSocketFactory,正在使用默认 java 信任库中已经存在的一些证书,在 jre/lib/security/cacerts 中找到在 java SDK 安装中。由于我必须创建自己的信任库和 keystore 来设置 RmiSSLSocketFactory,因此我假设 Smack 库代码无法找到它需要的任何证书。

所以我决定做的是将 cacerts 中可用的所有证书导入我自己的 keystore 。为此,我运行了:

keytool -importkeystore -srckeystore "c:\Program Files\Java\jdk1.7.0_25\jre\lib\security\cacerts" -destkeystore my_truststore  -srcstorepass changeit -deststorepass mypass

在那之后,一切顺利,两个安全连接均已顺利建立。

我希望这对以后的人有帮助。

关于java - 设置多个 SSL 套接字工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25725991/

相关文章:

java - 编写 Java RMI 聊天应用程序时出现 NotBoundException :-/

java RMI与非java实体通信?

java - Spring Security ACL 层次结构

java - 读取 .jar 中的资源文件时出现问题

ssl - Jmeter 分布式测试不适用于双向 SSL 握手

Python SSL 未知 CA 错误

java - 找不到 RMI 注册表

java - Hibernate - 两个类之间的多个多对多关联

java - 当我们有字符串池时为什么要进行字符串重复数据删除

java - 我在哪里可以找到 java truststore 文件?