< prev index next >

src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java

Print this page
@    rev 12977 : 6425769: jmx remote bind address
|\   Summary: Allow for binding to a specific address via custom socket factories.
| \
| |\
| | \
| | |\
+-+---o  rev 11054 : Merge
| | |/
+---o  rev 11053 : 8049367: Modular Run-Time Images
| |    Reviewed-by: chegar, dfuchs, ihse, joehw, mullan, psandoz, wetmore
| |    Contributed-by: alan.bateman@oracle.com, alex.buckley@oracle.com, bradford.wetmore@oracle.com, chris.hegarty@oracle.com, erik.joelsson@oracle.com, james.laskey@oracle.com, jonathan.gibbons@oracle.com, karen.kinnear@oracle.com, magnus.ihse.bursie@oracle.com, mandy.chung@oracle.com, mark.reinhold@oracle.com, paul.sandoz@oracle.com, sundararajan.athijegannathan@oracle.com
| o  rev 11007 : 8048050: Agent NullPointerException when rmi.port in use
|/   Reviewed-by: jbachorik, dfuchs
o  rev 10469 : 8054834: Modular Source Code
|  Reviewed-by: alanb, chegar, ihse, mduigou
|  Contributed-by: alan.bateman@oracle.com, alex.buckley@oracle.com, chris.hegarty@oracle.com, erik.joelsson@oracle.com, jonathan.gibbons@oracle.com, karen.kinnear@oracle.com, magnus.ihse.bursie@oracle.com, mandy.chung@oracle.com, mark.reinhold@oracle.com, paul.sandoz@oracle.com


  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.management.jmxremote;
  27 
  28 import java.io.BufferedInputStream;
  29 import java.io.File;
  30 import java.io.FileInputStream;
  31 import java.io.IOException;
  32 import java.io.InputStream;

  33 import java.lang.management.ManagementFactory;
  34 import java.net.InetAddress;
  35 import java.net.MalformedURLException;


  36 import java.net.UnknownHostException;
  37 import java.rmi.NoSuchObjectException;
  38 import java.rmi.Remote;
  39 import java.rmi.RemoteException;
  40 import java.rmi.registry.Registry;
  41 import java.rmi.server.RMIClientSocketFactory;
  42 import java.rmi.server.RMIServerSocketFactory;

  43 import java.rmi.server.RemoteObject;
  44 import java.rmi.server.UnicastRemoteObject;
  45 import java.security.KeyStore;
  46 import java.security.Principal;
  47 import java.util.HashMap;
  48 import java.util.HashSet;
  49 import java.util.Iterator;
  50 import java.util.Map;
  51 import java.util.Properties;
  52 import java.util.Set;
  53 import java.util.StringTokenizer;
  54 
  55 import javax.management.MBeanServer;
  56 import javax.management.remote.JMXAuthenticator;
  57 import javax.management.remote.JMXConnectorServer;
  58 import javax.management.remote.JMXConnectorServerFactory;
  59 import javax.management.remote.JMXServiceURL;
  60 import javax.management.remote.rmi.RMIConnectorServer;
  61 import javax.net.ssl.KeyManagerFactory;
  62 import javax.net.ssl.SSLContext;


  63 import javax.net.ssl.TrustManagerFactory;
  64 import javax.rmi.ssl.SslRMIClientSocketFactory;
  65 import javax.rmi.ssl.SslRMIServerSocketFactory;
  66 import javax.security.auth.Subject;
  67 
  68 import com.sun.jmx.remote.internal.RMIExporter;
  69 import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
  70 import com.sun.jmx.remote.util.ClassLogger;
  71 
  72 import sun.management.Agent;
  73 import sun.management.AgentConfigurationError;
  74 import static sun.management.AgentConfigurationError.*;
  75 import sun.management.ConnectorAddressLink;
  76 import sun.management.FileSystem;
  77 import sun.rmi.server.UnicastRef;
  78 import sun.rmi.server.UnicastServerRef;
  79 import sun.rmi.server.UnicastServerRef2;
  80 
  81 /**
  82  * This class initializes and starts the RMIConnectorServer for JSR 163


  90     public static interface DefaultValues {
  91 
  92         public static final String PORT = "0";
  93         public static final String CONFIG_FILE_NAME = "management.properties";
  94         public static final String USE_SSL = "true";
  95         public static final String USE_LOCAL_ONLY = "true";
  96         public static final String USE_REGISTRY_SSL = "false";
  97         public static final String USE_AUTHENTICATION = "true";
  98         public static final String PASSWORD_FILE_NAME = "jmxremote.password";
  99         public static final String ACCESS_FILE_NAME = "jmxremote.access";
 100         public static final String SSL_NEED_CLIENT_AUTH = "false";
 101     }
 102 
 103     /**
 104      * Names of JMX configuration properties.
 105      **/
 106     public static interface PropertyNames {
 107 
 108         public static final String PORT =
 109                 "com.sun.management.jmxremote.port";


 110         public static final String RMI_PORT =
 111                 "com.sun.management.jmxremote.rmi.port";
 112         public static final String CONFIG_FILE_NAME =
 113                 "com.sun.management.config.file";
 114         public static final String USE_LOCAL_ONLY =
 115                 "com.sun.management.jmxremote.local.only";
 116         public static final String USE_SSL =
 117                 "com.sun.management.jmxremote.ssl";
 118         public static final String USE_REGISTRY_SSL =
 119                 "com.sun.management.jmxremote.registry.ssl";
 120         public static final String USE_AUTHENTICATION =
 121                 "com.sun.management.jmxremote.authenticate";
 122         public static final String PASSWORD_FILE_NAME =
 123                 "com.sun.management.jmxremote.password.file";
 124         public static final String ACCESS_FILE_NAME =
 125                 "com.sun.management.jmxremote.access.file";
 126         public static final String LOGIN_CONFIG_NAME =
 127                 "com.sun.management.jmxremote.login.config";
 128         public static final String SSL_ENABLED_CIPHER_SUITES =
 129                 "com.sun.management.jmxremote.ssl.enabled.cipher.suites";


 407         if (useAuthentication) {
 408 
 409             // Get non-default login configuration
 410             loginConfigName =
 411                     props.getProperty(PropertyNames.LOGIN_CONFIG_NAME);
 412 
 413             if (loginConfigName == null) {
 414                 // Get password file
 415                 passwordFileName =
 416                         props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
 417                         getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
 418                 checkPasswordFile(passwordFileName);
 419             }
 420 
 421             // Get access file
 422             accessFileName = props.getProperty(PropertyNames.ACCESS_FILE_NAME,
 423                     getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
 424             checkAccessFile(accessFileName);
 425         }
 426 



 427         if (log.debugOn()) {
 428             log.debug("startRemoteConnectorServer",
 429                     Agent.getText("jmxremote.ConnectorBootstrap.starting") +
 430                     "\n\t" + PropertyNames.PORT + "=" + port +

 431                     "\n\t" + PropertyNames.RMI_PORT + "=" + rmiPort +
 432                     "\n\t" + PropertyNames.USE_SSL + "=" + useSsl +
 433                     "\n\t" + PropertyNames.USE_REGISTRY_SSL + "=" + useRegistrySsl +
 434                     "\n\t" + PropertyNames.SSL_CONFIG_FILE_NAME + "=" + sslConfigFileName +
 435                     "\n\t" + PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
 436                     enabledCipherSuites +
 437                     "\n\t" + PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
 438                     enabledProtocols +
 439                     "\n\t" + PropertyNames.SSL_NEED_CLIENT_AUTH + "=" +
 440                     sslNeedClientAuth +
 441                     "\n\t" + PropertyNames.USE_AUTHENTICATION + "=" +
 442                     useAuthentication +
 443                     (useAuthentication ? (loginConfigName == null ? ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
 444                     passwordFileName) : ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
 445                     loginConfigName)) : "\n\t" +
 446                     Agent.getText("jmxremote.ConnectorBootstrap.noAuthentication")) +
 447                     (useAuthentication ? ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
 448                     accessFileName) : "") +
 449                     "");
 450         }
 451 
 452         final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
 453         JMXConnectorServer cs = null;
 454         JMXServiceURL url = null;
 455         try {
 456             final JMXConnectorServerData data = exportMBeanServer(
 457                     mbs, port, rmiPort, useSsl, useRegistrySsl,
 458                     sslConfigFileName, enabledCipherSuitesList,
 459                     enabledProtocolsList, sslNeedClientAuth,
 460                     useAuthentication, loginConfigName,
 461                     passwordFileName, accessFileName);
 462             cs = data.jmxConnectorServer;
 463             url = data.jmxRemoteURL;
 464             log.config("startRemoteConnectorServer",
 465                     Agent.getText("jmxremote.ConnectorBootstrap.ready",
 466                     url.toString()));
 467         } catch (Exception e) {
 468             throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
 469         }
 470         try {
 471             // Export remote connector address and associated configuration
 472             // properties to the instrumentation buffer.
 473             Map<String, String> properties = new HashMap<>();
 474             properties.put("remoteAddress", url.toString());
 475             properties.put("authenticate", useAuthenticationStr);
 476             properties.put("ssl", useSslStr);
 477             properties.put("sslRegistry", useRegistrySslStr);
 478             properties.put("sslNeedClientAuth", sslNeedClientAuthStr);
 479             ConnectorAddressLink.exportRemote(properties);
 480         } catch (Exception e) {
 481             // Remote connector server started but unable to export remote


 611                     FILE_READ_FAILED, e, restrictedFileName);
 612         }
 613     }
 614 
 615     /**
 616      * Compute the full path name for a default file.
 617      * @param basename basename (with extension) of the default file.
 618      * @return ${JRE}/conf/management/${basename}
 619      **/
 620     private static String getDefaultFileName(String basename) {
 621         final String fileSeparator = File.separator;
 622         return System.getProperty("java.home") + fileSeparator + "conf" +
 623                 fileSeparator + "management" + fileSeparator +
 624                 basename;
 625     }
 626 
 627     private static SslRMIServerSocketFactory createSslRMIServerSocketFactory(
 628             String sslConfigFileName,
 629             String[] enabledCipherSuites,
 630             String[] enabledProtocols,
 631             boolean sslNeedClientAuth) {

 632         if (sslConfigFileName == null) {
 633             return new SslRMIServerSocketFactory(
 634                     enabledCipherSuites,
 635                     enabledProtocols,
 636                     sslNeedClientAuth);
 637         } else {
 638             checkRestrictedFile(sslConfigFileName);
 639             try {
 640                 // Load the SSL keystore properties from the config file
 641                 Properties p = new Properties();
 642                 try (InputStream in = new FileInputStream(sslConfigFileName)) {
 643                     BufferedInputStream bin = new BufferedInputStream(in);
 644                     p.load(bin);
 645                 }
 646                 String keyStore =
 647                         p.getProperty("javax.net.ssl.keyStore");
 648                 String keyStorePassword =
 649                         p.getProperty("javax.net.ssl.keyStorePassword", "");
 650                 String trustStore =
 651                         p.getProperty("javax.net.ssl.trustStore");
 652                 String trustStorePassword =
 653                         p.getProperty("javax.net.ssl.trustStorePassword", "");
 654 
 655                 char[] keyStorePasswd = null;
 656                 if (keyStorePassword.length() != 0) {


 670                     }
 671                 }
 672                 KeyManagerFactory kmf = KeyManagerFactory.getInstance(
 673                         KeyManagerFactory.getDefaultAlgorithm());
 674                 kmf.init(ks, keyStorePasswd);
 675 
 676                 KeyStore ts = null;
 677                 if (trustStore != null) {
 678                     ts = KeyStore.getInstance(KeyStore.getDefaultType());
 679                     try (FileInputStream tsfis = new FileInputStream(trustStore)) {
 680                         ts.load(tsfis, trustStorePasswd);
 681                     }
 682                 }
 683                 TrustManagerFactory tmf = TrustManagerFactory.getInstance(
 684                         TrustManagerFactory.getDefaultAlgorithm());
 685                 tmf.init(ts);
 686 
 687                 SSLContext ctx = SSLContext.getInstance("SSL");
 688                 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 689 
 690                 return new SslRMIServerSocketFactory(
 691                         ctx,
 692                         enabledCipherSuites,
 693                         enabledProtocols,
 694                         sslNeedClientAuth);
 695             } catch (Exception e) {
 696                 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
 697             }
 698         }
 699     }
 700 
 701     private static JMXConnectorServerData exportMBeanServer(
 702             MBeanServer mbs,
 703             int port,
 704             int rmiPort,
 705             boolean useSsl,
 706             boolean useRegistrySsl,
 707             String sslConfigFileName,
 708             String[] enabledCipherSuites,
 709             String[] enabledProtocols,
 710             boolean sslNeedClientAuth,
 711             boolean useAuthentication,
 712             String loginConfigName,
 713             String passwordFileName,
 714             String accessFileName)

 715             throws IOException, MalformedURLException {
 716 
 717         /* Make sure we use non-guessable RMI object IDs.  Otherwise
 718          * attackers could hijack open connections by guessing their
 719          * IDs.  */
 720         System.setProperty("java.rmi.server.randomIDs", "true");
 721 
 722         JMXServiceURL url = new JMXServiceURL("rmi", null, rmiPort);
 723 
 724         Map<String, Object> env = new HashMap<>();
 725 
 726         PermanentExporter exporter = new PermanentExporter();
 727 
 728         env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
 729 


 730         if (useAuthentication) {
 731             if (loginConfigName != null) {
 732                 env.put("jmx.remote.x.login.config", loginConfigName);
 733             }
 734             if (passwordFileName != null) {
 735                 env.put("jmx.remote.x.password.file", passwordFileName);
 736             }
 737 
 738             env.put("jmx.remote.x.access.file", accessFileName);
 739 
 740             if (env.get("jmx.remote.x.password.file") != null ||
 741                     env.get("jmx.remote.x.login.config") != null) {
 742                 env.put(JMXConnectorServer.AUTHENTICATOR,
 743                         new AccessFileCheckerAuthenticator(env));
 744             }
 745         }
 746 
 747         RMIClientSocketFactory csf = null;
 748         RMIServerSocketFactory ssf = null;
 749 
 750         if (useSsl || useRegistrySsl) {
 751             csf = new SslRMIClientSocketFactory();
 752             ssf = createSslRMIServerSocketFactory(
 753                     sslConfigFileName, enabledCipherSuites,
 754                     enabledProtocols, sslNeedClientAuth);
 755         }
 756 
 757         if (useSsl) {
 758             env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
 759                     csf);
 760             env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
 761                     ssf);
 762         }
 763 






 764         JMXConnectorServer connServer = null;
 765         try {
 766             connServer =
 767                     JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
 768             connServer.start();
 769         } catch (IOException e) {
 770             if (connServer == null || connServer.getAddress() == null) {
 771                 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
 772                         e, url.toString());
 773             } else {
 774                 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
 775                         e, connServer.getAddress().toString());
 776             }
 777         }
 778 
 779         if (useRegistrySsl) {
 780             registry =
 781                     new SingleEntryRegistry(port, csf, ssf,
 782                     "jmxrmi", exporter.firstExported);




 783         } else {
 784             registry =
 785                     new SingleEntryRegistry(port,
 786                     "jmxrmi", exporter.firstExported);
 787         }
 788 
 789 
 790         int registryPort =
 791             ((UnicastRef) ((RemoteObject) registry).getRef()).getLiveRef().getPort();
 792         String jmxUrlStr =  String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi",
 793                                            url.getHost(), registryPort);
 794         JMXServiceURL remoteURL = new JMXServiceURL(jmxUrlStr);
 795 
 796         /* Our exporter remembers the first object it was asked to
 797         export, which will be an RMIServerImpl appropriate for
 798         publication in our special registry.  We could
 799         alternatively have constructed the RMIServerImpl explicitly
 800         and then constructed an RMIConnectorServer passing it as a
 801         parameter, but that's quite a bit more verbose and pulls in
 802         lots of knowledge of the RMI connector.  */
 803 
 804         return new JMXConnectorServerData(connServer, remoteURL);
 805     }
 806 
 807     /**
 808      * This class cannot be instantiated.
 809      **/
 810     private ConnectorBootstrap() {
 811     }
 812 
 813     private static final ClassLogger log =
 814         new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
 815                         "ConnectorBootstrap");








































































































































































 816 }


  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.management.jmxremote;
  27 
  28 import java.io.BufferedInputStream;
  29 import java.io.File;
  30 import java.io.FileInputStream;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.io.Serializable;
  34 import java.lang.management.ManagementFactory;
  35 import java.net.InetAddress;
  36 import java.net.MalformedURLException;
  37 import java.net.Socket;
  38 import java.net.ServerSocket;
  39 import java.net.UnknownHostException;
  40 import java.rmi.NoSuchObjectException;
  41 import java.rmi.Remote;
  42 import java.rmi.RemoteException;
  43 import java.rmi.registry.Registry;
  44 import java.rmi.server.RMIClientSocketFactory;
  45 import java.rmi.server.RMIServerSocketFactory;
  46 import java.rmi.server.RMISocketFactory;
  47 import java.rmi.server.RemoteObject;
  48 import java.rmi.server.UnicastRemoteObject;
  49 import java.security.KeyStore;
  50 import java.security.Principal;
  51 import java.util.HashMap;
  52 import java.util.HashSet;
  53 import java.util.Iterator;
  54 import java.util.Map;
  55 import java.util.Properties;
  56 import java.util.Set;
  57 import java.util.StringTokenizer;
  58 
  59 import javax.management.MBeanServer;
  60 import javax.management.remote.JMXAuthenticator;
  61 import javax.management.remote.JMXConnectorServer;
  62 import javax.management.remote.JMXConnectorServerFactory;
  63 import javax.management.remote.JMXServiceURL;
  64 import javax.management.remote.rmi.RMIConnectorServer;
  65 import javax.net.ssl.KeyManagerFactory;
  66 import javax.net.ssl.SSLContext;
  67 import javax.net.ssl.SSLSocket;
  68 import javax.net.ssl.SSLSocketFactory;
  69 import javax.net.ssl.TrustManagerFactory;
  70 import javax.rmi.ssl.SslRMIClientSocketFactory;
  71 import javax.rmi.ssl.SslRMIServerSocketFactory;
  72 import javax.security.auth.Subject;
  73 
  74 import com.sun.jmx.remote.internal.RMIExporter;
  75 import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
  76 import com.sun.jmx.remote.util.ClassLogger;
  77 
  78 import sun.management.Agent;
  79 import sun.management.AgentConfigurationError;
  80 import static sun.management.AgentConfigurationError.*;
  81 import sun.management.ConnectorAddressLink;
  82 import sun.management.FileSystem;
  83 import sun.rmi.server.UnicastRef;
  84 import sun.rmi.server.UnicastServerRef;
  85 import sun.rmi.server.UnicastServerRef2;
  86 
  87 /**
  88  * This class initializes and starts the RMIConnectorServer for JSR 163


  96     public static interface DefaultValues {
  97 
  98         public static final String PORT = "0";
  99         public static final String CONFIG_FILE_NAME = "management.properties";
 100         public static final String USE_SSL = "true";
 101         public static final String USE_LOCAL_ONLY = "true";
 102         public static final String USE_REGISTRY_SSL = "false";
 103         public static final String USE_AUTHENTICATION = "true";
 104         public static final String PASSWORD_FILE_NAME = "jmxremote.password";
 105         public static final String ACCESS_FILE_NAME = "jmxremote.access";
 106         public static final String SSL_NEED_CLIENT_AUTH = "false";
 107     }
 108 
 109     /**
 110      * Names of JMX configuration properties.
 111      **/
 112     public static interface PropertyNames {
 113 
 114         public static final String PORT =
 115                 "com.sun.management.jmxremote.port";
 116         public static final String HOST =
 117                 "com.sun.management.jmxremote.host";
 118         public static final String RMI_PORT =
 119                 "com.sun.management.jmxremote.rmi.port";
 120         public static final String CONFIG_FILE_NAME =
 121                 "com.sun.management.config.file";
 122         public static final String USE_LOCAL_ONLY =
 123                 "com.sun.management.jmxremote.local.only";
 124         public static final String USE_SSL =
 125                 "com.sun.management.jmxremote.ssl";
 126         public static final String USE_REGISTRY_SSL =
 127                 "com.sun.management.jmxremote.registry.ssl";
 128         public static final String USE_AUTHENTICATION =
 129                 "com.sun.management.jmxremote.authenticate";
 130         public static final String PASSWORD_FILE_NAME =
 131                 "com.sun.management.jmxremote.password.file";
 132         public static final String ACCESS_FILE_NAME =
 133                 "com.sun.management.jmxremote.access.file";
 134         public static final String LOGIN_CONFIG_NAME =
 135                 "com.sun.management.jmxremote.login.config";
 136         public static final String SSL_ENABLED_CIPHER_SUITES =
 137                 "com.sun.management.jmxremote.ssl.enabled.cipher.suites";


 415         if (useAuthentication) {
 416 
 417             // Get non-default login configuration
 418             loginConfigName =
 419                     props.getProperty(PropertyNames.LOGIN_CONFIG_NAME);
 420 
 421             if (loginConfigName == null) {
 422                 // Get password file
 423                 passwordFileName =
 424                         props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
 425                         getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
 426                 checkPasswordFile(passwordFileName);
 427             }
 428 
 429             // Get access file
 430             accessFileName = props.getProperty(PropertyNames.ACCESS_FILE_NAME,
 431                     getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
 432             checkAccessFile(accessFileName);
 433         }
 434 
 435         final String bindAddress =
 436                 props.getProperty(PropertyNames.HOST);
 437 
 438         if (log.debugOn()) {
 439             log.debug("startRemoteConnectorServer",
 440                     Agent.getText("jmxremote.ConnectorBootstrap.starting") +
 441                     "\n\t" + PropertyNames.PORT + "=" + port +
 442                     "\n\t" + PropertyNames.HOST + "=" + bindAddress +
 443                     "\n\t" + PropertyNames.RMI_PORT + "=" + rmiPort +
 444                     "\n\t" + PropertyNames.USE_SSL + "=" + useSsl +
 445                     "\n\t" + PropertyNames.USE_REGISTRY_SSL + "=" + useRegistrySsl +
 446                     "\n\t" + PropertyNames.SSL_CONFIG_FILE_NAME + "=" + sslConfigFileName +
 447                     "\n\t" + PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
 448                     enabledCipherSuites +
 449                     "\n\t" + PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
 450                     enabledProtocols +
 451                     "\n\t" + PropertyNames.SSL_NEED_CLIENT_AUTH + "=" +
 452                     sslNeedClientAuth +
 453                     "\n\t" + PropertyNames.USE_AUTHENTICATION + "=" +
 454                     useAuthentication +
 455                     (useAuthentication ? (loginConfigName == null ? ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
 456                     passwordFileName) : ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
 457                     loginConfigName)) : "\n\t" +
 458                     Agent.getText("jmxremote.ConnectorBootstrap.noAuthentication")) +
 459                     (useAuthentication ? ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
 460                     accessFileName) : "") +
 461                     "");
 462         }
 463 
 464         final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
 465         JMXConnectorServer cs = null;
 466         JMXServiceURL url = null;
 467         try {
 468             final JMXConnectorServerData data = exportMBeanServer(
 469                     mbs, port, rmiPort, useSsl, useRegistrySsl,
 470                     sslConfigFileName, enabledCipherSuitesList,
 471                     enabledProtocolsList, sslNeedClientAuth,
 472                     useAuthentication, loginConfigName,
 473                     passwordFileName, accessFileName, bindAddress);
 474             cs = data.jmxConnectorServer;
 475             url = data.jmxRemoteURL;
 476             log.config("startRemoteConnectorServer",
 477                     Agent.getText("jmxremote.ConnectorBootstrap.ready",
 478                     url.toString()));
 479         } catch (Exception e) {
 480             throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
 481         }
 482         try {
 483             // Export remote connector address and associated configuration
 484             // properties to the instrumentation buffer.
 485             Map<String, String> properties = new HashMap<>();
 486             properties.put("remoteAddress", url.toString());
 487             properties.put("authenticate", useAuthenticationStr);
 488             properties.put("ssl", useSslStr);
 489             properties.put("sslRegistry", useRegistrySslStr);
 490             properties.put("sslNeedClientAuth", sslNeedClientAuthStr);
 491             ConnectorAddressLink.exportRemote(properties);
 492         } catch (Exception e) {
 493             // Remote connector server started but unable to export remote


 623                     FILE_READ_FAILED, e, restrictedFileName);
 624         }
 625     }
 626 
 627     /**
 628      * Compute the full path name for a default file.
 629      * @param basename basename (with extension) of the default file.
 630      * @return ${JRE}/conf/management/${basename}
 631      **/
 632     private static String getDefaultFileName(String basename) {
 633         final String fileSeparator = File.separator;
 634         return System.getProperty("java.home") + fileSeparator + "conf" +
 635                 fileSeparator + "management" + fileSeparator +
 636                 basename;
 637     }
 638 
 639     private static SslRMIServerSocketFactory createSslRMIServerSocketFactory(
 640             String sslConfigFileName,
 641             String[] enabledCipherSuites,
 642             String[] enabledProtocols,
 643             boolean sslNeedClientAuth,
 644             String bindAddress) {
 645         if (sslConfigFileName == null) {
 646             return new HostAwareSslSocketFactory(
 647                     enabledCipherSuites,
 648                     enabledProtocols,
 649                     sslNeedClientAuth, bindAddress);
 650         } else {
 651             checkRestrictedFile(sslConfigFileName);
 652             try {
 653                 // Load the SSL keystore properties from the config file
 654                 Properties p = new Properties();
 655                 try (InputStream in = new FileInputStream(sslConfigFileName)) {
 656                     BufferedInputStream bin = new BufferedInputStream(in);
 657                     p.load(bin);
 658                 }
 659                 String keyStore =
 660                         p.getProperty("javax.net.ssl.keyStore");
 661                 String keyStorePassword =
 662                         p.getProperty("javax.net.ssl.keyStorePassword", "");
 663                 String trustStore =
 664                         p.getProperty("javax.net.ssl.trustStore");
 665                 String trustStorePassword =
 666                         p.getProperty("javax.net.ssl.trustStorePassword", "");
 667 
 668                 char[] keyStorePasswd = null;
 669                 if (keyStorePassword.length() != 0) {


 683                     }
 684                 }
 685                 KeyManagerFactory kmf = KeyManagerFactory.getInstance(
 686                         KeyManagerFactory.getDefaultAlgorithm());
 687                 kmf.init(ks, keyStorePasswd);
 688 
 689                 KeyStore ts = null;
 690                 if (trustStore != null) {
 691                     ts = KeyStore.getInstance(KeyStore.getDefaultType());
 692                     try (FileInputStream tsfis = new FileInputStream(trustStore)) {
 693                         ts.load(tsfis, trustStorePasswd);
 694                     }
 695                 }
 696                 TrustManagerFactory tmf = TrustManagerFactory.getInstance(
 697                         TrustManagerFactory.getDefaultAlgorithm());
 698                 tmf.init(ts);
 699 
 700                 SSLContext ctx = SSLContext.getInstance("SSL");
 701                 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 702 
 703                 return new HostAwareSslSocketFactory(
 704                         ctx,
 705                         enabledCipherSuites,
 706                         enabledProtocols,
 707                         sslNeedClientAuth, bindAddress);
 708             } catch (Exception e) {
 709                 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
 710             }
 711         }
 712     }
 713 
 714     private static JMXConnectorServerData exportMBeanServer(
 715             MBeanServer mbs,
 716             int port,
 717             int rmiPort,
 718             boolean useSsl,
 719             boolean useRegistrySsl,
 720             String sslConfigFileName,
 721             String[] enabledCipherSuites,
 722             String[] enabledProtocols,
 723             boolean sslNeedClientAuth,
 724             boolean useAuthentication,
 725             String loginConfigName,
 726             String passwordFileName,
 727             String accessFileName,
 728             String bindAddress)
 729             throws IOException, MalformedURLException {
 730 
 731         /* Make sure we use non-guessable RMI object IDs.  Otherwise
 732          * attackers could hijack open connections by guessing their
 733          * IDs.  */
 734         System.setProperty("java.rmi.server.randomIDs", "true");
 735 
 736         JMXServiceURL url = new JMXServiceURL("rmi", bindAddress, rmiPort);
 737 
 738         Map<String, Object> env = new HashMap<>();
 739 
 740         PermanentExporter exporter = new PermanentExporter();
 741 
 742         env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
 743 
 744         boolean useSocketFactory = bindAddress != null && !useSsl;
 745 
 746         if (useAuthentication) {
 747             if (loginConfigName != null) {
 748                 env.put("jmx.remote.x.login.config", loginConfigName);
 749             }
 750             if (passwordFileName != null) {
 751                 env.put("jmx.remote.x.password.file", passwordFileName);
 752             }
 753 
 754             env.put("jmx.remote.x.access.file", accessFileName);
 755 
 756             if (env.get("jmx.remote.x.password.file") != null ||
 757                     env.get("jmx.remote.x.login.config") != null) {
 758                 env.put(JMXConnectorServer.AUTHENTICATOR,
 759                         new AccessFileCheckerAuthenticator(env));
 760             }
 761         }
 762 
 763         RMIClientSocketFactory csf = null;
 764         RMIServerSocketFactory ssf = null;
 765 
 766         if (useSsl || useRegistrySsl) {
 767             csf = new SslRMIClientSocketFactory();
 768             ssf = createSslRMIServerSocketFactory(
 769                     sslConfigFileName, enabledCipherSuites,
 770                     enabledProtocols, sslNeedClientAuth, bindAddress);
 771         }
 772 
 773         if (useSsl) {
 774             env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
 775                     csf);
 776             env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
 777                     ssf);
 778         }
 779 
 780         if (useSocketFactory) {
 781             ssf = new HostAwareSocketFactory(bindAddress);
 782             env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
 783                     ssf);
 784         }
 785 
 786         JMXConnectorServer connServer = null;
 787         try {
 788             connServer =
 789                     JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
 790             connServer.start();
 791         } catch (IOException e) {
 792             if (connServer == null || connServer.getAddress() == null) {
 793                 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
 794                         e, url.toString());
 795             } else {
 796                 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
 797                         e, connServer.getAddress().toString());
 798             }
 799         }
 800 
 801         if (useRegistrySsl) {
 802             registry =
 803                     new SingleEntryRegistry(port, csf, ssf,
 804                     "jmxrmi", exporter.firstExported);
 805         } else if (useSocketFactory) {
 806             registry =
 807                     new SingleEntryRegistry(port, csf, ssf,
 808                     "jmxrmi", exporter.firstExported);
 809         } else {
 810             registry =
 811                     new SingleEntryRegistry(port,
 812                     "jmxrmi", exporter.firstExported);
 813         }
 814 
 815 
 816         int registryPort =
 817             ((UnicastRef) ((RemoteObject) registry).getRef()).getLiveRef().getPort();
 818         String jmxUrlStr =  String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi",
 819                                            url.getHost(), registryPort);
 820         JMXServiceURL remoteURL = new JMXServiceURL(jmxUrlStr);
 821 
 822         /* Our exporter remembers the first object it was asked to
 823         export, which will be an RMIServerImpl appropriate for
 824         publication in our special registry.  We could
 825         alternatively have constructed the RMIServerImpl explicitly
 826         and then constructed an RMIConnectorServer passing it as a
 827         parameter, but that's quite a bit more verbose and pulls in
 828         lots of knowledge of the RMI connector.  */
 829 
 830         return new JMXConnectorServerData(connServer, remoteURL);
 831     }
 832 
 833     /**
 834      * This class cannot be instantiated.
 835      **/
 836     private ConnectorBootstrap() {
 837     }
 838 
 839     private static final ClassLogger log =
 840         new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
 841                         "ConnectorBootstrap");
 842 
 843     private static class HostAwareSocketFactory implements RMIServerSocketFactory {
 844 
 845         private final String bindAddress;
 846 
 847         private HostAwareSocketFactory(String bindAddress) {
 848              this.bindAddress = bindAddress;
 849         }
 850 
 851         @Override
 852         public ServerSocket createServerSocket(int port) throws IOException {
 853             if (bindAddress == null) {
 854                 return new ServerSocket(port);
 855             } else {
 856                 try {
 857                     InetAddress addr = InetAddress.getByName(bindAddress);
 858                     return new ServerSocket(port, 0, addr);
 859                 } catch (UnknownHostException e) {
 860                     return new ServerSocket(port);
 861                 }
 862             }
 863         }
 864     }
 865 
 866     private static class HostAwareSslSocketFactory extends SslRMIServerSocketFactory {
 867 
 868         private final String bindAddress;
 869         private final String[] enabledCipherSuites;
 870         private final String[] enabledProtocols;
 871         private final boolean needClientAuth;
 872         private final SSLContext context;
 873 
 874         private HostAwareSslSocketFactory(String[] enabledCipherSuites,
 875                                           String[] enabledProtocols,
 876                                           boolean sslNeedClientAuth,
 877                                           String bindAddress) throws IllegalArgumentException {
 878             this(null, enabledCipherSuites, enabledProtocols, sslNeedClientAuth, bindAddress);
 879         }
 880 
 881         private HostAwareSslSocketFactory(SSLContext ctx,
 882                                           String[] enabledCipherSuites,
 883                                           String[] enabledProtocols,
 884                                           boolean sslNeedClientAuth,
 885                                           String bindAddress) throws IllegalArgumentException {
 886             this.context = ctx;
 887             this.bindAddress = bindAddress;
 888             this.enabledProtocols = enabledProtocols;
 889             this.enabledCipherSuites = enabledCipherSuites;
 890             this.needClientAuth = sslNeedClientAuth;
 891             checkValues(ctx, enabledCipherSuites, enabledProtocols);
 892         }
 893 
 894         @Override
 895         public ServerSocket createServerSocket(int port) throws IOException {
 896             if (bindAddress != null) {
 897                 try {
 898                     InetAddress addr = InetAddress.getByName(bindAddress);
 899                     return new SslServerSocket(port, 0, addr, context,
 900                                                enabledCipherSuites, enabledProtocols, needClientAuth);
 901                 } catch (UnknownHostException e) {
 902                     return new SslServerSocket(port, context,
 903                                                enabledCipherSuites, enabledProtocols, needClientAuth);
 904                 }
 905             } else {
 906                 return new SslServerSocket(port, context,
 907                                            enabledCipherSuites, enabledProtocols, needClientAuth);
 908             }
 909         }
 910 
 911         private static void checkValues(SSLContext context,
 912                                         String[] enabledCipherSuites,
 913                                         String[] enabledProtocols) throws IllegalArgumentException {
 914             // Force the initialization of the default at construction time,
 915             // rather than delaying it to the first time createServerSocket()
 916             // is called.
 917             //
 918             final SSLSocketFactory sslSocketFactory =
 919                     context == null ?
 920                         (SSLSocketFactory)SSLSocketFactory.getDefault() : context.getSocketFactory();
 921             SSLSocket sslSocket = null;
 922             if (enabledCipherSuites != null || enabledProtocols != null) {
 923                 try {
 924                     sslSocket = (SSLSocket) sslSocketFactory.createSocket();
 925                 } catch (Exception e) {
 926                     final String msg = "Unable to check if the cipher suites " +
 927                             "and protocols to enable are supported";
 928                     throw (IllegalArgumentException)
 929                     new IllegalArgumentException(msg).initCause(e);
 930                 }
 931             }
 932 
 933             // Check if all the cipher suites and protocol versions to enable
 934             // are supported by the underlying SSL/TLS implementation and if
 935             // true create lists from arrays.
 936             //
 937             if (enabledCipherSuites != null) {
 938                 sslSocket.setEnabledCipherSuites(enabledCipherSuites);
 939             }
 940             if (enabledProtocols != null) {
 941                 sslSocket.setEnabledProtocols(enabledProtocols);
 942             }
 943         }
 944     }
 945 
 946     private static class SslServerSocket extends ServerSocket {
 947 
 948         private static SSLSocketFactory defaultSSLSocketFactory;
 949         private final String[] enabledCipherSuites;
 950         private final String[] enabledProtocols;
 951         private final boolean needClientAuth;
 952         private final SSLContext context;
 953 
 954         private SslServerSocket(int port,
 955                                 SSLContext ctx,
 956                                 String[] enabledCipherSuites,
 957                                 String[] enabledProtocols,
 958                                 boolean needClientAuth) throws IOException {
 959             super(port);
 960             this.enabledProtocols = enabledProtocols;
 961             this.enabledCipherSuites = enabledCipherSuites;
 962             this.needClientAuth = needClientAuth;
 963             this.context = ctx;
 964         }
 965 
 966         private SslServerSocket(int port,
 967                                 int backlog,
 968                                 InetAddress bindAddr,
 969                                 SSLContext ctx,
 970                                 String[] enabledCipherSuites,
 971                                 String[] enabledProtocols,
 972                                 boolean needClientAuth) throws IOException {
 973             super(port, backlog, bindAddr);
 974             this.enabledProtocols = enabledProtocols;
 975             this.enabledCipherSuites = enabledCipherSuites;
 976             this.needClientAuth = needClientAuth;
 977             this.context = ctx;
 978         }
 979 
 980         @Override
 981         public Socket accept() throws IOException {
 982             final SSLSocketFactory sslSocketFactory =
 983                     context == null ?
 984                         getDefaultSSLSocketFactory() : context.getSocketFactory();
 985             Socket socket = super.accept();
 986             SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
 987                     socket, socket.getInetAddress().getHostName(),
 988                     socket.getPort(), true);
 989             sslSocket.setUseClientMode(false);
 990             if (enabledCipherSuites != null) {
 991                 sslSocket.setEnabledCipherSuites(enabledCipherSuites);
 992             }
 993             if (enabledProtocols != null) {
 994                 sslSocket.setEnabledProtocols(enabledProtocols);
 995             }
 996             sslSocket.setNeedClientAuth(needClientAuth);
 997             return sslSocket;
 998         }
 999 
1000         private static synchronized SSLSocketFactory getDefaultSSLSocketFactory() {
1001             if (defaultSSLSocketFactory == null) {
1002                 defaultSSLSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
1003                 return defaultSSLSocketFactory;
1004             } else {
1005                 return defaultSSLSocketFactory;
1006             }
1007         }
1008  
1009     }
1010 }
< prev index next >