--- a/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java Mon Feb 06 17:19:06 2017 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1016 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.management.jmxremote;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-import java.lang.management.ManagementFactory;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.Socket;
-import java.net.ServerSocket;
-import java.net.UnknownHostException;
-import java.rmi.NoSuchObjectException;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.rmi.registry.Registry;
-import java.rmi.server.RMIClientSocketFactory;
-import java.rmi.server.RMIServerSocketFactory;
-import java.rmi.server.RMISocketFactory;
-import java.rmi.server.RemoteObject;
-import java.rmi.server.UnicastRemoteObject;
-import java.security.KeyStore;
-import java.security.Principal;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.StringTokenizer;
-
-import javax.management.MBeanServer;
-import javax.management.remote.JMXAuthenticator;
-import javax.management.remote.JMXConnectorServer;
-import javax.management.remote.JMXConnectorServerFactory;
-import javax.management.remote.JMXServiceURL;
-import javax.management.remote.rmi.RMIConnectorServer;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManagerFactory;
-import javax.rmi.ssl.SslRMIClientSocketFactory;
-import javax.rmi.ssl.SslRMIServerSocketFactory;
-import javax.security.auth.Subject;
-
-import com.sun.jmx.remote.internal.RMIExporter;
-import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
-import com.sun.jmx.remote.util.ClassLogger;
-
-import sun.management.Agent;
-import sun.management.AgentConfigurationError;
-import static sun.management.AgentConfigurationError.*;
-import sun.management.ConnectorAddressLink;
-import sun.management.FileSystem;
-import sun.rmi.server.UnicastRef;
-import sun.rmi.server.UnicastServerRef;
-import sun.rmi.server.UnicastServerRef2;
-
-/**
- * This class initializes and starts the RMIConnectorServer for JSR 163
- * JMX Monitoring.
- **/
-public final class ConnectorBootstrap {
-
- /**
- * Default values for JMX configuration properties.
- **/
- public static interface DefaultValues {
-
- public static final String PORT = "0";
- public static final String CONFIG_FILE_NAME = "management.properties";
- public static final String USE_SSL = "true";
- public static final String USE_LOCAL_ONLY = "true";
- public static final String USE_REGISTRY_SSL = "false";
- public static final String USE_AUTHENTICATION = "true";
- public static final String PASSWORD_FILE_NAME = "jmxremote.password";
- public static final String ACCESS_FILE_NAME = "jmxremote.access";
- public static final String SSL_NEED_CLIENT_AUTH = "false";
- }
-
- /**
- * Names of JMX configuration properties.
- **/
- public static interface PropertyNames {
-
- public static final String PORT =
- "com.sun.management.jmxremote.port";
- public static final String HOST =
- "com.sun.management.jmxremote.host";
- public static final String RMI_PORT =
- "com.sun.management.jmxremote.rmi.port";
- public static final String CONFIG_FILE_NAME =
- "com.sun.management.config.file";
- public static final String USE_LOCAL_ONLY =
- "com.sun.management.jmxremote.local.only";
- public static final String USE_SSL =
- "com.sun.management.jmxremote.ssl";
- public static final String USE_REGISTRY_SSL =
- "com.sun.management.jmxremote.registry.ssl";
- public static final String USE_AUTHENTICATION =
- "com.sun.management.jmxremote.authenticate";
- public static final String PASSWORD_FILE_NAME =
- "com.sun.management.jmxremote.password.file";
- public static final String ACCESS_FILE_NAME =
- "com.sun.management.jmxremote.access.file";
- public static final String LOGIN_CONFIG_NAME =
- "com.sun.management.jmxremote.login.config";
- public static final String SSL_ENABLED_CIPHER_SUITES =
- "com.sun.management.jmxremote.ssl.enabled.cipher.suites";
- public static final String SSL_ENABLED_PROTOCOLS =
- "com.sun.management.jmxremote.ssl.enabled.protocols";
- public static final String SSL_NEED_CLIENT_AUTH =
- "com.sun.management.jmxremote.ssl.need.client.auth";
- public static final String SSL_CONFIG_FILE_NAME =
- "com.sun.management.jmxremote.ssl.config.file";
- }
-
- /**
- * JMXConnectorServer associated data.
- */
- private static class JMXConnectorServerData {
-
- public JMXConnectorServerData(
- JMXConnectorServer jmxConnectorServer,
- JMXServiceURL jmxRemoteURL) {
- this.jmxConnectorServer = jmxConnectorServer;
- this.jmxRemoteURL = jmxRemoteURL;
- }
- JMXConnectorServer jmxConnectorServer;
- JMXServiceURL jmxRemoteURL;
- }
-
- /**
- * <p>Prevents our RMI server objects from keeping the JVM alive.</p>
- *
- * <p>We use a private interface in Sun's JMX Remote API implementation
- * that allows us to specify how to export RMI objects. We do so using
- * UnicastServerRef, a class in Sun's RMI implementation. This is all
- * non-portable, of course, so this is only valid because we are inside
- * Sun's JRE.</p>
- *
- * <p>Objects are exported using {@link
- * UnicastServerRef#exportObject(Remote, Object, boolean)}. The
- * boolean parameter is called <code>permanent</code> and means
- * both that the object is not eligible for Distributed Garbage
- * Collection, and that its continued existence will not prevent
- * the JVM from exiting. It is the latter semantics we want (we
- * already have the former because of the way the JMX Remote API
- * works). Hence the somewhat misleading name of this class.</p>
- */
- private static class PermanentExporter implements RMIExporter {
-
- public Remote exportObject(Remote obj,
- int port,
- RMIClientSocketFactory csf,
- RMIServerSocketFactory ssf)
- throws RemoteException {
-
- synchronized (this) {
- if (firstExported == null) {
- firstExported = obj;
- }
- }
-
- final UnicastServerRef ref;
- if (csf == null && ssf == null) {
- ref = new UnicastServerRef(port);
- } else {
- ref = new UnicastServerRef2(port, csf, ssf);
- }
- return ref.exportObject(obj, null, true);
- }
-
- // Nothing special to be done for this case
- public boolean unexportObject(Remote obj, boolean force)
- throws NoSuchObjectException {
- return UnicastRemoteObject.unexportObject(obj, force);
- }
- Remote firstExported;
- }
-
- /**
- * This JMXAuthenticator wraps the JMXPluggableAuthenticator and verifies
- * that at least one of the principal names contained in the authenticated
- * Subject is present in the access file.
- */
- private static class AccessFileCheckerAuthenticator
- implements JMXAuthenticator {
-
- public AccessFileCheckerAuthenticator(Map<String, Object> env) throws IOException {
- environment = env;
- accessFile = (String) env.get("jmx.remote.x.access.file");
- properties = propertiesFromFile(accessFile);
- }
-
- public Subject authenticate(Object credentials) {
- final JMXAuthenticator authenticator =
- new JMXPluggableAuthenticator(environment);
- final Subject subject = authenticator.authenticate(credentials);
- checkAccessFileEntries(subject);
- return subject;
- }
-
- private void checkAccessFileEntries(Subject subject) {
- if (subject == null) {
- throw new SecurityException(
- "Access denied! No matching entries found in " +
- "the access file [" + accessFile + "] as the " +
- "authenticated Subject is null");
- }
- final Set<Principal> principals = subject.getPrincipals();
- for (Principal p1: principals) {
- if (properties.containsKey(p1.getName())) {
- return;
- }
- }
-
- final Set<String> principalsStr = new HashSet<>();
- for (Principal p2: principals) {
- principalsStr.add(p2.getName());
- }
- throw new SecurityException(
- "Access denied! No entries found in the access file [" +
- accessFile + "] for any of the authenticated identities " +
- principalsStr);
- }
-
- private static Properties propertiesFromFile(String fname)
- throws IOException {
- Properties p = new Properties();
- if (fname == null) {
- return p;
- }
- try (FileInputStream fin = new FileInputStream(fname)) {
- p.load(fin);
- }
- return p;
- }
- private final Map<String, Object> environment;
- private final Properties properties;
- private final String accessFile;
- }
-
- // The variable below is here to support stop functionality
- // It would be overriten if you call startRemoteCommectionServer second
- // time. It's OK for now as logic in Agent.java forbids mutiple agents
- private static Registry registry = null;
-
- public static void unexportRegistry() {
- // Remove the entry from registry
- try {
- if (registry != null) {
- UnicastRemoteObject.unexportObject(registry, true);
- registry = null;
- }
- } catch(NoSuchObjectException ex) {
- // This exception can appears only if we attempt
- // to unexportRegistry second time. So it's safe
- // to ignore it without additional messages.
- }
- }
-
- /**
- * Initializes and starts the JMX Connector Server.
- * If the com.sun.management.jmxremote.port property is not defined,
- * simply return. Otherwise, attempts to load the config file, and
- * then calls {@link #startRemoteConnectorServer
- * (java.lang.String, java.util.Properties)}.
- *
- * This method is used by some jtreg tests.
- **/
- public static synchronized JMXConnectorServer initialize() {
-
- // Load a new management properties
- final Properties props = Agent.loadManagementProperties();
- if (props == null) {
- return null;
- }
-
- final String portStr = props.getProperty(PropertyNames.PORT);
- return startRemoteConnectorServer(portStr, props);
- }
-
- /**
- * This method is used by some jtreg tests.
- *
- * @see #startRemoteConnectorServer
- * (String portStr, Properties props)
- */
- public static synchronized JMXConnectorServer initialize(String portStr, Properties props) {
- return startRemoteConnectorServer(portStr, props);
- }
-
- /**
- * Initializes and starts a JMX Connector Server for remote
- * monitoring and management.
- **/
- public static synchronized JMXConnectorServer startRemoteConnectorServer(String portStr, Properties props) {
-
- // Get port number
- final int port;
- try {
- port = Integer.parseInt(portStr);
- } catch (NumberFormatException x) {
- throw new AgentConfigurationError(INVALID_JMXREMOTE_PORT, x, portStr);
- }
- if (port < 0) {
- throw new AgentConfigurationError(INVALID_JMXREMOTE_PORT, portStr);
- }
-
- // User can specify a port to be used to export rmi object,
- // in order to simplify firewall rules
- // if port is not specified random one will be allocated.
- int rmiPort = 0;
- String rmiPortStr = props.getProperty(PropertyNames.RMI_PORT);
- try {
- if (rmiPortStr != null) {
- rmiPort = Integer.parseInt(rmiPortStr);
- }
- } catch (NumberFormatException x) {
- throw new AgentConfigurationError(INVALID_JMXREMOTE_RMI_PORT, x, rmiPortStr);
- }
- if (rmiPort < 0) {
- throw new AgentConfigurationError(INVALID_JMXREMOTE_RMI_PORT, rmiPortStr);
- }
-
- // Do we use authentication?
- final String useAuthenticationStr =
- props.getProperty(PropertyNames.USE_AUTHENTICATION,
- DefaultValues.USE_AUTHENTICATION);
- final boolean useAuthentication =
- Boolean.valueOf(useAuthenticationStr).booleanValue();
-
- // Do we use SSL?
- final String useSslStr =
- props.getProperty(PropertyNames.USE_SSL,
- DefaultValues.USE_SSL);
- final boolean useSsl =
- Boolean.valueOf(useSslStr).booleanValue();
-
- // Do we use RMI Registry SSL?
- final String useRegistrySslStr =
- props.getProperty(PropertyNames.USE_REGISTRY_SSL,
- DefaultValues.USE_REGISTRY_SSL);
- final boolean useRegistrySsl =
- Boolean.valueOf(useRegistrySslStr).booleanValue();
-
- final String enabledCipherSuites =
- props.getProperty(PropertyNames.SSL_ENABLED_CIPHER_SUITES);
- String enabledCipherSuitesList[] = null;
- if (enabledCipherSuites != null) {
- StringTokenizer st = new StringTokenizer(enabledCipherSuites, ",");
- int tokens = st.countTokens();
- enabledCipherSuitesList = new String[tokens];
- for (int i = 0; i < tokens; i++) {
- enabledCipherSuitesList[i] = st.nextToken();
- }
- }
-
- final String enabledProtocols =
- props.getProperty(PropertyNames.SSL_ENABLED_PROTOCOLS);
- String enabledProtocolsList[] = null;
- if (enabledProtocols != null) {
- StringTokenizer st = new StringTokenizer(enabledProtocols, ",");
- int tokens = st.countTokens();
- enabledProtocolsList = new String[tokens];
- for (int i = 0; i < tokens; i++) {
- enabledProtocolsList[i] = st.nextToken();
- }
- }
-
- final String sslNeedClientAuthStr =
- props.getProperty(PropertyNames.SSL_NEED_CLIENT_AUTH,
- DefaultValues.SSL_NEED_CLIENT_AUTH);
- final boolean sslNeedClientAuth =
- Boolean.valueOf(sslNeedClientAuthStr).booleanValue();
-
- // Read SSL config file name
- final String sslConfigFileName =
- props.getProperty(PropertyNames.SSL_CONFIG_FILE_NAME);
-
- String loginConfigName = null;
- String passwordFileName = null;
- String accessFileName = null;
-
- // Initialize settings when authentication is active
- if (useAuthentication) {
-
- // Get non-default login configuration
- loginConfigName =
- props.getProperty(PropertyNames.LOGIN_CONFIG_NAME);
-
- if (loginConfigName == null) {
- // Get password file
- passwordFileName =
- props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
- getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
- checkPasswordFile(passwordFileName);
- }
-
- // Get access file
- accessFileName = props.getProperty(PropertyNames.ACCESS_FILE_NAME,
- getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
- checkAccessFile(accessFileName);
- }
-
- final String bindAddress =
- props.getProperty(PropertyNames.HOST);
-
- if (log.debugOn()) {
- log.debug("startRemoteConnectorServer",
- Agent.getText("jmxremote.ConnectorBootstrap.starting") +
- "\n\t" + PropertyNames.PORT + "=" + port +
- (bindAddress == null ? "" : "\n\t" + PropertyNames.HOST + "=" + bindAddress) +
- "\n\t" + PropertyNames.RMI_PORT + "=" + rmiPort +
- "\n\t" + PropertyNames.USE_SSL + "=" + useSsl +
- "\n\t" + PropertyNames.USE_REGISTRY_SSL + "=" + useRegistrySsl +
- "\n\t" + PropertyNames.SSL_CONFIG_FILE_NAME + "=" + sslConfigFileName +
- "\n\t" + PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
- enabledCipherSuites +
- "\n\t" + PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
- enabledProtocols +
- "\n\t" + PropertyNames.SSL_NEED_CLIENT_AUTH + "=" +
- sslNeedClientAuth +
- "\n\t" + PropertyNames.USE_AUTHENTICATION + "=" +
- useAuthentication +
- (useAuthentication ? (loginConfigName == null ? ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
- passwordFileName) : ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
- loginConfigName)) : "\n\t" +
- Agent.getText("jmxremote.ConnectorBootstrap.noAuthentication")) +
- (useAuthentication ? ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
- accessFileName) : "") +
- "");
- }
-
- final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- JMXConnectorServer cs = null;
- JMXServiceURL url = null;
- try {
- final JMXConnectorServerData data = exportMBeanServer(
- mbs, port, rmiPort, useSsl, useRegistrySsl,
- sslConfigFileName, enabledCipherSuitesList,
- enabledProtocolsList, sslNeedClientAuth,
- useAuthentication, loginConfigName,
- passwordFileName, accessFileName, bindAddress);
- cs = data.jmxConnectorServer;
- url = data.jmxRemoteURL;
- log.config("startRemoteConnectorServer",
- Agent.getText("jmxremote.ConnectorBootstrap.ready",
- url.toString()));
- } catch (Exception e) {
- throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
- }
- try {
- // Export remote connector address and associated configuration
- // properties to the instrumentation buffer.
- Map<String, String> properties = new HashMap<>();
- properties.put("remoteAddress", url.toString());
- properties.put("authenticate", useAuthenticationStr);
- properties.put("ssl", useSslStr);
- properties.put("sslRegistry", useRegistrySslStr);
- properties.put("sslNeedClientAuth", sslNeedClientAuthStr);
- ConnectorAddressLink.exportRemote(properties);
- } catch (Exception e) {
- // Remote connector server started but unable to export remote
- // connector address and associated configuration properties to
- // the instrumentation buffer - non-fatal error.
- log.debug("startRemoteConnectorServer", e);
- }
- return cs;
- }
-
- /*
- * Creates and starts a RMI Connector Server for "local" monitoring
- * and management.
- */
- public static JMXConnectorServer startLocalConnectorServer() {
- // Ensure cryptographically strong random number generater used
- // to choose the object number - see java.rmi.server.ObjID
- System.setProperty("java.rmi.server.randomIDs", "true");
-
- // This RMI server should not keep the VM alive
- Map<String, Object> env = new HashMap<>();
- env.put(RMIExporter.EXPORTER_ATTRIBUTE, new PermanentExporter());
- env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{
- String[].class.getName(), String.class.getName()
- });
-
- // The local connector server need only be available via the
- // loopback connection.
- String localhost = "localhost";
- InetAddress lh = null;
- try {
- lh = InetAddress.getByName(localhost);
- localhost = lh.getHostAddress();
- } catch (UnknownHostException x) {
- }
-
- // localhost unknown or (somehow) didn't resolve to
- // a loopback address.
- if (lh == null || !lh.isLoopbackAddress()) {
- localhost = "127.0.0.1";
- }
-
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- try {
- JMXServiceURL url = new JMXServiceURL("rmi", localhost, 0);
- // Do we accept connections from local interfaces only?
- Properties props = Agent.getManagementProperties();
- if (props == null) {
- props = new Properties();
- }
- String useLocalOnlyStr = props.getProperty(
- PropertyNames.USE_LOCAL_ONLY, DefaultValues.USE_LOCAL_ONLY);
- boolean useLocalOnly = Boolean.valueOf(useLocalOnlyStr).booleanValue();
- if (useLocalOnly) {
- env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
- new LocalRMIServerSocketFactory());
- }
- JMXConnectorServer server =
- JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
- server.start();
- return server;
- } catch (Exception e) {
- throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
- }
- }
-
- private static void checkPasswordFile(String passwordFileName) {
- if (passwordFileName == null || passwordFileName.length() == 0) {
- throw new AgentConfigurationError(PASSWORD_FILE_NOT_SET);
- }
- File file = new File(passwordFileName);
- if (!file.exists()) {
- throw new AgentConfigurationError(PASSWORD_FILE_NOT_FOUND, passwordFileName);
- }
-
- if (!file.canRead()) {
- throw new AgentConfigurationError(PASSWORD_FILE_NOT_READABLE, passwordFileName);
- }
-
- FileSystem fs = FileSystem.open();
- try {
- if (fs.supportsFileSecurity(file)) {
- if (!fs.isAccessUserOnly(file)) {
- final String msg = Agent.getText("jmxremote.ConnectorBootstrap.password.readonly",
- passwordFileName);
- log.config("startRemoteConnectorServer", msg);
- throw new AgentConfigurationError(PASSWORD_FILE_ACCESS_NOT_RESTRICTED,
- passwordFileName);
- }
- }
- } catch (IOException e) {
- throw new AgentConfigurationError(PASSWORD_FILE_READ_FAILED,
- e, passwordFileName);
- }
- }
-
- private static void checkAccessFile(String accessFileName) {
- if (accessFileName == null || accessFileName.length() == 0) {
- throw new AgentConfigurationError(ACCESS_FILE_NOT_SET);
- }
- File file = new File(accessFileName);
- if (!file.exists()) {
- throw new AgentConfigurationError(ACCESS_FILE_NOT_FOUND, accessFileName);
- }
-
- if (!file.canRead()) {
- throw new AgentConfigurationError(ACCESS_FILE_NOT_READABLE, accessFileName);
- }
- }
-
- private static void checkRestrictedFile(String restrictedFileName) {
- if (restrictedFileName == null || restrictedFileName.length() == 0) {
- throw new AgentConfigurationError(FILE_NOT_SET);
- }
- File file = new File(restrictedFileName);
- if (!file.exists()) {
- throw new AgentConfigurationError(FILE_NOT_FOUND, restrictedFileName);
- }
- if (!file.canRead()) {
- throw new AgentConfigurationError(FILE_NOT_READABLE, restrictedFileName);
- }
- FileSystem fs = FileSystem.open();
- try {
- if (fs.supportsFileSecurity(file)) {
- if (!fs.isAccessUserOnly(file)) {
- final String msg = Agent.getText(
- "jmxremote.ConnectorBootstrap.file.readonly",
- restrictedFileName);
- log.config("startRemoteConnectorServer", msg);
- throw new AgentConfigurationError(
- FILE_ACCESS_NOT_RESTRICTED, restrictedFileName);
- }
- }
- } catch (IOException e) {
- throw new AgentConfigurationError(
- FILE_READ_FAILED, e, restrictedFileName);
- }
- }
-
- /**
- * Compute the full path name for a default file.
- * @param basename basename (with extension) of the default file.
- * @return ${JRE}/conf/management/${basename}
- **/
- private static String getDefaultFileName(String basename) {
- final String fileSeparator = File.separator;
- return System.getProperty("java.home") + fileSeparator + "conf" +
- fileSeparator + "management" + fileSeparator +
- basename;
- }
-
- private static SslRMIServerSocketFactory createSslRMIServerSocketFactory(
- String sslConfigFileName,
- String[] enabledCipherSuites,
- String[] enabledProtocols,
- boolean sslNeedClientAuth,
- String bindAddress) {
- if (sslConfigFileName == null) {
- return new HostAwareSslSocketFactory(
- enabledCipherSuites,
- enabledProtocols,
- sslNeedClientAuth, bindAddress);
- } else {
- checkRestrictedFile(sslConfigFileName);
- try {
- // Load the SSL keystore properties from the config file
- Properties p = new Properties();
- try (InputStream in = new FileInputStream(sslConfigFileName)) {
- BufferedInputStream bin = new BufferedInputStream(in);
- p.load(bin);
- }
- String keyStore =
- p.getProperty("javax.net.ssl.keyStore");
- String keyStorePassword =
- p.getProperty("javax.net.ssl.keyStorePassword", "");
- String trustStore =
- p.getProperty("javax.net.ssl.trustStore");
- String trustStorePassword =
- p.getProperty("javax.net.ssl.trustStorePassword", "");
-
- 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());
- try (FileInputStream ksfis = new FileInputStream(keyStore)) {
- ks.load(ksfis, keyStorePasswd);
- }
- }
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(
- KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(ks, keyStorePasswd);
-
- KeyStore ts = null;
- if (trustStore != null) {
- ts = KeyStore.getInstance(KeyStore.getDefaultType());
- try (FileInputStream tsfis = new FileInputStream(trustStore)) {
- ts.load(tsfis, trustStorePasswd);
- }
- }
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(
- TrustManagerFactory.getDefaultAlgorithm());
- tmf.init(ts);
-
- SSLContext ctx = SSLContext.getInstance("SSL");
- ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
-
- return new HostAwareSslSocketFactory(
- ctx,
- enabledCipherSuites,
- enabledProtocols,
- sslNeedClientAuth, bindAddress);
- } catch (Exception e) {
- throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
- }
- }
- }
-
- private static JMXConnectorServerData exportMBeanServer(
- MBeanServer mbs,
- int port,
- int rmiPort,
- boolean useSsl,
- boolean useRegistrySsl,
- String sslConfigFileName,
- String[] enabledCipherSuites,
- String[] enabledProtocols,
- boolean sslNeedClientAuth,
- boolean useAuthentication,
- String loginConfigName,
- String passwordFileName,
- String accessFileName,
- String bindAddress)
- throws IOException, MalformedURLException {
-
- /* Make sure we use non-guessable RMI object IDs. Otherwise
- * attackers could hijack open connections by guessing their
- * IDs. */
- System.setProperty("java.rmi.server.randomIDs", "true");
-
- JMXServiceURL url = new JMXServiceURL("rmi", bindAddress, rmiPort);
-
- Map<String, Object> env = new HashMap<>();
-
- PermanentExporter exporter = new PermanentExporter();
-
- env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
- env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{
- String[].class.getName(), String.class.getName()
- });
-
- boolean useSocketFactory = bindAddress != null && !useSsl;
-
- if (useAuthentication) {
- if (loginConfigName != null) {
- env.put("jmx.remote.x.login.config", loginConfigName);
- }
- if (passwordFileName != null) {
- env.put("jmx.remote.x.password.file", passwordFileName);
- }
-
- env.put("jmx.remote.x.access.file", accessFileName);
-
- if (env.get("jmx.remote.x.password.file") != null ||
- env.get("jmx.remote.x.login.config") != null) {
- env.put(JMXConnectorServer.AUTHENTICATOR,
- new AccessFileCheckerAuthenticator(env));
- }
- }
-
- RMIClientSocketFactory csf = null;
- RMIServerSocketFactory ssf = null;
-
- if (useSsl || useRegistrySsl) {
- csf = new SslRMIClientSocketFactory();
- ssf = createSslRMIServerSocketFactory(
- sslConfigFileName, enabledCipherSuites,
- enabledProtocols, sslNeedClientAuth, bindAddress);
- }
-
- if (useSsl) {
- env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
- csf);
- env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
- ssf);
- }
-
- if (useSocketFactory) {
- ssf = new HostAwareSocketFactory(bindAddress);
- env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
- ssf);
- }
-
- JMXConnectorServer connServer = null;
- try {
- connServer =
- JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
- connServer.start();
- } catch (IOException e) {
- if (connServer == null || connServer.getAddress() == null) {
- throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
- e, url.toString());
- } else {
- throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
- e, connServer.getAddress().toString());
- }
- }
-
- if (useRegistrySsl) {
- registry =
- new SingleEntryRegistry(port, csf, ssf,
- "jmxrmi", exporter.firstExported);
- } else if (useSocketFactory) {
- registry =
- new SingleEntryRegistry(port, csf, ssf,
- "jmxrmi", exporter.firstExported);
- } else {
- registry =
- new SingleEntryRegistry(port,
- "jmxrmi", exporter.firstExported);
- }
-
-
- int registryPort =
- ((UnicastRef) ((RemoteObject) registry).getRef()).getLiveRef().getPort();
- String jmxUrlStr = String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi",
- url.getHost(), registryPort);
- JMXServiceURL remoteURL = new JMXServiceURL(jmxUrlStr);
-
- /* Our exporter remembers the first object it was asked to
- export, which will be an RMIServerImpl appropriate for
- publication in our special registry. We could
- alternatively have constructed the RMIServerImpl explicitly
- and then constructed an RMIConnectorServer passing it as a
- parameter, but that's quite a bit more verbose and pulls in
- lots of knowledge of the RMI connector. */
-
- return new JMXConnectorServerData(connServer, remoteURL);
- }
-
- /**
- * This class cannot be instantiated.
- **/
- private ConnectorBootstrap() {
- }
-
- private static final ClassLogger log =
- new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
- "ConnectorBootstrap");
-
- private static class HostAwareSocketFactory implements RMIServerSocketFactory {
-
- private final String bindAddress;
-
- private HostAwareSocketFactory(String bindAddress) {
- this.bindAddress = bindAddress;
- }
-
- @Override
- public ServerSocket createServerSocket(int port) throws IOException {
- if (bindAddress == null) {
- return new ServerSocket(port);
- } else {
- try {
- InetAddress addr = InetAddress.getByName(bindAddress);
- return new ServerSocket(port, 0, addr);
- } catch (UnknownHostException e) {
- return new ServerSocket(port);
- }
- }
- }
- }
-
- private static class HostAwareSslSocketFactory extends SslRMIServerSocketFactory {
-
- private final String bindAddress;
- private final String[] enabledCipherSuites;
- private final String[] enabledProtocols;
- private final boolean needClientAuth;
- private final SSLContext context;
-
- private HostAwareSslSocketFactory(String[] enabledCipherSuites,
- String[] enabledProtocols,
- boolean sslNeedClientAuth,
- String bindAddress) throws IllegalArgumentException {
- this(null, enabledCipherSuites, enabledProtocols, sslNeedClientAuth, bindAddress);
- }
-
- private HostAwareSslSocketFactory(SSLContext ctx,
- String[] enabledCipherSuites,
- String[] enabledProtocols,
- boolean sslNeedClientAuth,
- String bindAddress) throws IllegalArgumentException {
- this.context = ctx;
- this.bindAddress = bindAddress;
- this.enabledProtocols = enabledProtocols;
- this.enabledCipherSuites = enabledCipherSuites;
- this.needClientAuth = sslNeedClientAuth;
- checkValues(ctx, enabledCipherSuites, enabledProtocols);
- }
-
- @Override
- public ServerSocket createServerSocket(int port) throws IOException {
- if (bindAddress != null) {
- try {
- InetAddress addr = InetAddress.getByName(bindAddress);
- return new SslServerSocket(port, 0, addr, context,
- enabledCipherSuites, enabledProtocols, needClientAuth);
- } catch (UnknownHostException e) {
- return new SslServerSocket(port, context,
- enabledCipherSuites, enabledProtocols, needClientAuth);
- }
- } else {
- return new SslServerSocket(port, context,
- enabledCipherSuites, enabledProtocols, needClientAuth);
- }
- }
-
- private static void checkValues(SSLContext context,
- String[] enabledCipherSuites,
- String[] enabledProtocols) throws IllegalArgumentException {
- // Force the initialization of the default at construction time,
- // rather than delaying it to the first time createServerSocket()
- // is called.
- //
- final SSLSocketFactory sslSocketFactory =
- context == null ?
- (SSLSocketFactory)SSLSocketFactory.getDefault() : context.getSocketFactory();
- SSLSocket sslSocket = null;
- if (enabledCipherSuites != null || enabledProtocols != null) {
- try {
- sslSocket = (SSLSocket) sslSocketFactory.createSocket();
- } catch (Exception e) {
- final String msg = "Unable to check if the cipher suites " +
- "and protocols to enable are supported";
- throw (IllegalArgumentException)
- new IllegalArgumentException(msg).initCause(e);
- }
- }
-
- // Check if all the cipher suites and protocol versions to enable
- // are supported by the underlying SSL/TLS implementation and if
- // true create lists from arrays.
- //
- if (enabledCipherSuites != null) {
- sslSocket.setEnabledCipherSuites(enabledCipherSuites);
- }
- if (enabledProtocols != null) {
- sslSocket.setEnabledProtocols(enabledProtocols);
- }
- }
- }
-
- private static class SslServerSocket extends ServerSocket {
-
- private static SSLSocketFactory defaultSSLSocketFactory;
- private final String[] enabledCipherSuites;
- private final String[] enabledProtocols;
- private final boolean needClientAuth;
- private final SSLContext context;
-
- private SslServerSocket(int port,
- SSLContext ctx,
- String[] enabledCipherSuites,
- String[] enabledProtocols,
- boolean needClientAuth) throws IOException {
- super(port);
- this.enabledProtocols = enabledProtocols;
- this.enabledCipherSuites = enabledCipherSuites;
- this.needClientAuth = needClientAuth;
- this.context = ctx;
- }
-
- private SslServerSocket(int port,
- int backlog,
- InetAddress bindAddr,
- SSLContext ctx,
- String[] enabledCipherSuites,
- String[] enabledProtocols,
- boolean needClientAuth) throws IOException {
- super(port, backlog, bindAddr);
- this.enabledProtocols = enabledProtocols;
- this.enabledCipherSuites = enabledCipherSuites;
- this.needClientAuth = needClientAuth;
- this.context = ctx;
- }
-
- @Override
- public Socket accept() throws IOException {
- final SSLSocketFactory sslSocketFactory =
- context == null ?
- getDefaultSSLSocketFactory() : context.getSocketFactory();
- Socket socket = super.accept();
- SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
- socket, socket.getInetAddress().getHostName(),
- socket.getPort(), true);
- sslSocket.setUseClientMode(false);
- if (enabledCipherSuites != null) {
- sslSocket.setEnabledCipherSuites(enabledCipherSuites);
- }
- if (enabledProtocols != null) {
- sslSocket.setEnabledProtocols(enabledProtocols);
- }
- sslSocket.setNeedClientAuth(needClientAuth);
- return sslSocket;
- }
-
- private static synchronized SSLSocketFactory getDefaultSSLSocketFactory() {
- if (defaultSSLSocketFactory == null) {
- defaultSSLSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
- return defaultSSLSocketFactory;
- } else {
- return defaultSSLSocketFactory;
- }
- }
-
- }
-}