【问题标题】:JMX with SSL without using system properties使用 SSL 的 JMX,不使用系统属性
【发布时间】:2025-12-07 18:10:01
【问题描述】:

我花了很多时间将支持 JMX 添加到企业应用程序中。 JMX 应该通过 SQL 使用 SSL 和客户端身份验证。那不是问题。 我正在使用系统属性来启用 SSL。 系统属性对于 JVM 来说是全局的。尤其是在大型应用程序中,如果没有其他配置方法可用,很快就会出现冲突。

特别是在大型企业应用程序中,需要对需要不同证书的不同服务进行调用,尤其是在自动证书选择方面存在限制,需要有一种方法可以在需要时通过灵活的代码挂钩。 不幸的是,JMX 和 RMI 目前没有提供这样的钩子,完全依赖于系统属性或默认的套接字工厂。

有什么方法可以通过不使用系统属性来使用 SSL 来制作 JMX?

编辑:

使用 SslRMIClientSocketFactory 不起作用。

//          System.setProperty( "java.rmi.server.randomIDs", "true" );
//          System.setProperty( "javax.net.ssl.keyStore", keystore );
//          System.setProperty( "javax.net.ssl.keyStorePassword",
//              "password" );

          // SSL-based RMI socket factories.
          SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
          SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory();
          map.put( RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf );
          map.put( RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf );

例外:

java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: 
    javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:304)

【问题讨论】:

    标签: java ssl rmi jmx keystore


    【解决方案1】:

    您可以创建自己的RMIConnectorServer,并有条件地为 SSL 启用它。在构建服务器实例时,环境映射可以加载定义的RMIClientSocketFactoryRMIServerSocketFactory 实例。要启用 SSL,可以将这些工厂设置为配置的 SslRMIClientSocketFactorySslRMIServerSocketFactory 实例,您将重新创建等效于系统道具配置的连接器服务器。我没有用 SSL 做这件事,但它似乎有据可查。

    【讨论】:

    • 结果:java.rmi.ConnectIOException。请在下面查看我的编辑。
    • 您需要为 SSL 工厂提供配置,而不是无参数的 ctor。
    【解决方案2】:

    解决办法:

    SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
        SslRMIServerSocketFactory ssf = createSslRMIServerSocketFactory(null,null,false);
        map.put( RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf );
        map.put( RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf );    
    
    ....
    
    private static SslRMIServerSocketFactory createSslRMIServerSocketFactory(
              String[] enabledCipherSuites, String[] enabledProtocols,
              boolean sslNeedClientAuth )
          {
              try
              {
                // Load the SSL keystore properties from the config file
                String keyStore =  "KeyStore.jks";
                String keyStorePassword = "pass";
                String trustStore = "truststore";
                String trustStorePassword = "pass";
    
                char[] keyStorePasswd = null;
                if ( keyStorePassword.length() != 0 )
                {
                  keyStorePasswd = keyStorePassword.toCharArray();
                }
    
                char[] trustStorePasswd = null;
                if ( trustStorePassword.length() != 0 )
                {
                  trustStorePasswd = trustStorePassword.toCharArray();
                }
    
                KeyStore ks = null;
                if ( keyStore != null )
                {
                  ks = KeyStore.getInstance( KeyStore.getDefaultType() );
                  FileInputStream ksfis = new FileInputStream( keyStore );
                  try
                  {
                    ks.load( ksfis, keyStorePasswd );
                  }
                  finally
                  {
                    ksfis.close();
                  }
                }
                KeyManagerFactory kmf = KeyManagerFactory.getInstance( KeyManagerFactory
                    .getDefaultAlgorithm() );
                kmf.init( ks, keyStorePasswd );
    
                KeyStore ts = null;
                if ( trustStore != null )
                {
                  ts = KeyStore.getInstance( KeyStore.getDefaultType() );
                  FileInputStream tsfis = new FileInputStream( trustStore );
                  try
                  {
                    ts.load( tsfis, trustStorePasswd );
                  }
                  finally
                  {
                    tsfis.close();
                  }
                }
                TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory
                    .getDefaultAlgorithm() );
                tmf.init( (KeyStore) ts );
    
                SSLContext ctx = SSLContext.getInstance( "SSL" );
                ctx.init( kmf.getKeyManagers(), tmf.getTrustManagers(), null );
    
                return new SslRMIServerSocketFactory ( ctx, enabledCipherSuites, enabledProtocols,
                    sslNeedClientAuth );
              }
              catch ( Exception e )
              {
                Logger.getGlobal().log( Level.SEVERE, e.getMessage() );
                return null;
              }
            }
    

    【讨论】: