History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/management/jmxremote/ConnectorBootstrap.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/management/jmxremote/ConnectorBootstrap.java+785−0
@@ -0,0 +1,785 @@
1/*
2 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
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
26package sun.management.jmxremote;
27
28import java.io.BufferedInputStream;
29import java.io.File;
30import java.io.FileInputStream;
31import java.io.InputStream;
32import java.io.IOException;
33
34import java.net.InetAddress;
35import java.net.MalformedURLException;
36import java.net.UnknownHostException;
37
38import java.rmi.NoSuchObjectException;
39import java.rmi.Remote;
40import java.rmi.RemoteException;
41import java.rmi.registry.Registry;
42import java.rmi.server.RemoteObject;
43import java.rmi.server.RMIClientSocketFactory;
44import java.rmi.server.RMIServerSocketFactory;
45import java.rmi.server.UnicastRemoteObject;
46
47import java.security.KeyStore;
48import java.security.Principal;
49
50import java.util.HashMap;
51import java.util.HashSet;
52import java.util.Iterator;
53import java.util.Map;
54import java.util.Properties;
55import java.util.Set;
56import java.util.StringTokenizer;
57
58import java.lang.management.ManagementFactory;
59
60import javax.net.ssl.*;
61
62import javax.management.MBeanServer;
63import javax.management.remote.JMXAuthenticator;
64import javax.management.remote.JMXConnectorServer;
65import javax.management.remote.JMXConnectorServerFactory;
66import javax.management.remote.JMXServiceURL;
67import javax.management.remote.rmi.RMIConnectorServer;
68
69import javax.rmi.ssl.SslRMIClientSocketFactory;
70import javax.rmi.ssl.SslRMIServerSocketFactory;
71
72import javax.security.auth.Subject;
73
74import sun.rmi.server.UnicastRef;
75import sun.rmi.server.UnicastServerRef;
76import sun.rmi.server.UnicastServerRef2;
77
78import sun.management.Agent;
79import sun.management.AgentConfigurationError;
80import static sun.management.AgentConfigurationError.*;
81import sun.management.ConnectorAddressLink;
82import sun.management.FileSystem;
83import com.sun.jmx.remote.util.ClassLogger;
84
85import com.sun.jmx.remote.internal.RMIExporter;
86import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
87
88/**
89 * This class initializes and starts the RMIConnectorServer for JSR 163
90 * JMX Monitoring.
91 **/
92public final class ConnectorBootstrap {
93
94 /**
95 * Default values for JMX configuration properties.
96 **/
97 public static interface DefaultValues {
98
99 public static final String PORT = "0";
100 public static final String CONFIG_FILE_NAME = "management.properties";
101 public static final String USE_SSL = "true";
102 public static final String USE_LOCAL_ONLY = "true";
103 public static final String USE_REGISTRY_SSL = "false";
104 public static final String USE_AUTHENTICATION = "true";
105 public static final String PASSWORD_FILE_NAME = "jmxremote.password";
106 public static final String ACCESS_FILE_NAME = "jmxremote.access";
107 public static final String SSL_NEED_CLIENT_AUTH = "false";
108 }
109
110 /**
111 * Names of JMX configuration properties.
112 **/
113 public static interface PropertyNames {
114
115 public static final String PORT =
116 "com.sun.management.jmxremote.port";
117 public static final String CONFIG_FILE_NAME =
118 "com.sun.management.config.file";
119 public static final String USE_LOCAL_ONLY =
120 "com.sun.management.jmxremote.local.only";
121 public static final String USE_SSL =
122 "com.sun.management.jmxremote.ssl";
123 public static final String USE_REGISTRY_SSL =
124 "com.sun.management.jmxremote.registry.ssl";
125 public static final String USE_AUTHENTICATION =
126 "com.sun.management.jmxremote.authenticate";
127 public static final String PASSWORD_FILE_NAME =
128 "com.sun.management.jmxremote.password.file";
129 public static final String ACCESS_FILE_NAME =
130 "com.sun.management.jmxremote.access.file";
131 public static final String LOGIN_CONFIG_NAME =
132 "com.sun.management.jmxremote.login.config";
133 public static final String SSL_ENABLED_CIPHER_SUITES =
134 "com.sun.management.jmxremote.ssl.enabled.cipher.suites";
135 public static final String SSL_ENABLED_PROTOCOLS =
136 "com.sun.management.jmxremote.ssl.enabled.protocols";
137 public static final String SSL_NEED_CLIENT_AUTH =
138 "com.sun.management.jmxremote.ssl.need.client.auth";
139 public static final String SSL_CONFIG_FILE_NAME =
140 "com.sun.management.jmxremote.ssl.config.file";
141 }
142
143 /**
144 * JMXConnectorServer associated data.
145 */
146 private static class JMXConnectorServerData {
147
148 public JMXConnectorServerData(
149 JMXConnectorServer jmxConnectorServer,
150 JMXServiceURL jmxRemoteURL) {
151 this.jmxConnectorServer = jmxConnectorServer;
152 this.jmxRemoteURL = jmxRemoteURL;
153 }
154 JMXConnectorServer jmxConnectorServer;
155 JMXServiceURL jmxRemoteURL;
156 }
157
158 /**
159 * <p>Prevents our RMI server objects from keeping the JVM alive.</p>
160 *
161 * <p>We use a private interface in Sun's JMX Remote API implementation
162 * that allows us to specify how to export RMI objects. We do so using
163 * UnicastServerRef, a class in Sun's RMI implementation. This is all
164 * non-portable, of course, so this is only valid because we are inside
165 * Sun's JRE.</p>
166 *
167 * <p>Objects are exported using {@link
168 * UnicastServerRef#exportObject(Remote, Object, boolean)}. The
169 * boolean parameter is called <code>permanent</code> and means
170 * both that the object is not eligible for Distributed Garbage
171 * Collection, and that its continued existence will not prevent
172 * the JVM from exiting. It is the latter semantics we want (we
173 * already have the former because of the way the JMX Remote API
174 * works). Hence the somewhat misleading name of this class.</p>
175 */
176 private static class PermanentExporter implements RMIExporter {
177
178 public Remote exportObject(Remote obj,
179 int port,
180 RMIClientSocketFactory csf,
181 RMIServerSocketFactory ssf)
182 throws RemoteException {
183
184 synchronized (this) {
185 if (firstExported == null) {
186 firstExported = obj;
187 }
188 }
189
190 final UnicastServerRef ref;
191 if (csf == null && ssf == null) {
192 ref = new UnicastServerRef(port);
193 } else {
194 ref = new UnicastServerRef2(port, csf, ssf);
195 }
196 return ref.exportObject(obj, null, true);
197 }
198
199 // Nothing special to be done for this case
200 public boolean unexportObject(Remote obj, boolean force)
201 throws NoSuchObjectException {
202 return UnicastRemoteObject.unexportObject(obj, force);
203 }
204 Remote firstExported;
205 }
206
207 /**
208 * This JMXAuthenticator wraps the JMXPluggableAuthenticator and verifies
209 * that at least one of the principal names contained in the authenticated
210 * Subject is present in the access file.
211 */
212 private static class AccessFileCheckerAuthenticator
213 implements JMXAuthenticator {
214
215 public AccessFileCheckerAuthenticator(Map<String, Object> env) throws IOException {
216 environment = env;
217 accessFile = (String) env.get("jmx.remote.x.access.file");
218 properties = propertiesFromFile(accessFile);
219 }
220
221 public Subject authenticate(Object credentials) {
222 final JMXAuthenticator authenticator =
223 new JMXPluggableAuthenticator(environment);
224 final Subject subject = authenticator.authenticate(credentials);
225 checkAccessFileEntries(subject);
226 return subject;
227 }
228
229 private void checkAccessFileEntries(Subject subject) {
230 if (subject == null) {
231 throw new SecurityException(
232 "Access denied! No matching entries found in " +
233 "the access file [" + accessFile + "] as the " +
234 "authenticated Subject is null");
235 }
236 final Set principals = subject.getPrincipals();
237 for (Iterator i = principals.iterator(); i.hasNext();) {
238 final Principal p = (Principal) i.next();
239 if (properties.containsKey(p.getName())) {
240 return;
241 }
242 }
243 final Set<String> principalsStr = new HashSet<String>();
244 for (Iterator i = principals.iterator(); i.hasNext();) {
245 final Principal p = (Principal) i.next();
246 principalsStr.add(p.getName());
247 }
248 throw new SecurityException(
249 "Access denied! No entries found in the access file [" +
250 accessFile + "] for any of the authenticated identities " +
251 principalsStr);
252 }
253
254 private static Properties propertiesFromFile(String fname)
255 throws IOException {
256 Properties p = new Properties();
257 if (fname == null) {
258 return p;
259 }
260 FileInputStream fin = new FileInputStream(fname);
261 p.load(fin);
262 fin.close();
263 return p;
264 }
265 private final Map<String, Object> environment;
266 private final Properties properties;
267 private final String accessFile;
268 }
269
270 /**
271 * Initializes and starts the JMX Connector Server.
272 * If the com.sun.management.jmxremote.port property is not defined,
273 * simply return. Otherwise, attempts to load the config file, and
274 * then calls {@link #initialize(java.lang.String, java.util.Properties)}.
275 *
276 **/
277 public static synchronized JMXConnectorServer initialize() {
278
279 // Load a new management properties
280 final Properties props = Agent.loadManagementProperties();
281 if (props == null) {
282 return null;
283 }
284
285 final String portStr = props.getProperty(PropertyNames.PORT);
286
287
288 // System.out.println("initializing: {port=" + portStr + ",
289 // properties="+props+"}");
290 return initialize(portStr, props);
291 }
292
293 /**
294 * Initializes and starts a JMX Connector Server for remote
295 * monitoring and management.
296 **/
297 public static synchronized JMXConnectorServer initialize(String portStr, Properties props) {
298
299 // Get port number
300 final int port;
301 try {
302 port = Integer.parseInt(portStr);
303 } catch (NumberFormatException x) {
304 throw new AgentConfigurationError(INVALID_JMXREMOTE_PORT, x, portStr);
305 }
306 if (port < 0) {
307 throw new AgentConfigurationError(INVALID_JMXREMOTE_PORT, portStr);
308 }
309
310 // Do we use authentication?
311 final String useAuthenticationStr =
312 props.getProperty(PropertyNames.USE_AUTHENTICATION,
313 DefaultValues.USE_AUTHENTICATION);
314 final boolean useAuthentication =
315 Boolean.valueOf(useAuthenticationStr).booleanValue();
316
317 // Do we use SSL?
318 final String useSslStr =
319 props.getProperty(PropertyNames.USE_SSL,
320 DefaultValues.USE_SSL);
321 final boolean useSsl =
322 Boolean.valueOf(useSslStr).booleanValue();
323
324 // Do we use RMI Registry SSL?
325 final String useRegistrySslStr =
326 props.getProperty(PropertyNames.USE_REGISTRY_SSL,
327 DefaultValues.USE_REGISTRY_SSL);
328 final boolean useRegistrySsl =
329 Boolean.valueOf(useRegistrySslStr).booleanValue();
330
331 final String enabledCipherSuites =
332 props.getProperty(PropertyNames.SSL_ENABLED_CIPHER_SUITES);
333 String enabledCipherSuitesList[] = null;
334 if (enabledCipherSuites != null) {
335 StringTokenizer st = new StringTokenizer(enabledCipherSuites, ",");
336 int tokens = st.countTokens();
337 enabledCipherSuitesList = new String[tokens];
338 for (int i = 0; i < tokens; i++) {
339 enabledCipherSuitesList[i] = st.nextToken();
340 }
341 }
342
343 final String enabledProtocols =
344 props.getProperty(PropertyNames.SSL_ENABLED_PROTOCOLS);
345 String enabledProtocolsList[] = null;
346 if (enabledProtocols != null) {
347 StringTokenizer st = new StringTokenizer(enabledProtocols, ",");
348 int tokens = st.countTokens();
349 enabledProtocolsList = new String[tokens];
350 for (int i = 0; i < tokens; i++) {
351 enabledProtocolsList[i] = st.nextToken();
352 }
353 }
354
355 final String sslNeedClientAuthStr =
356 props.getProperty(PropertyNames.SSL_NEED_CLIENT_AUTH,
357 DefaultValues.SSL_NEED_CLIENT_AUTH);
358 final boolean sslNeedClientAuth =
359 Boolean.valueOf(sslNeedClientAuthStr).booleanValue();
360
361 // Read SSL config file name
362 final String sslConfigFileName =
363 props.getProperty(PropertyNames.SSL_CONFIG_FILE_NAME);
364
365 String loginConfigName = null;
366 String passwordFileName = null;
367 String accessFileName = null;
368
369 // Initialize settings when authentication is active
370 if (useAuthentication) {
371
372 // Get non-default login configuration
373 loginConfigName =
374 props.getProperty(PropertyNames.LOGIN_CONFIG_NAME);
375
376 if (loginConfigName == null) {
377 // Get password file
378 passwordFileName =
379 props.getProperty(PropertyNames.PASSWORD_FILE_NAME,
380 getDefaultFileName(DefaultValues.PASSWORD_FILE_NAME));
381 checkPasswordFile(passwordFileName);
382 }
383
384 // Get access file
385 accessFileName = props.getProperty(PropertyNames.ACCESS_FILE_NAME,
386 getDefaultFileName(DefaultValues.ACCESS_FILE_NAME));
387 checkAccessFile(accessFileName);
388 }
389
390 if (log.debugOn()) {
391 log.debug("initialize",
392 Agent.getText("jmxremote.ConnectorBootstrap.initialize") +
393 "\n\t" + PropertyNames.PORT + "=" + port +
394 "\n\t" + PropertyNames.USE_SSL + "=" + useSsl +
395 "\n\t" + PropertyNames.USE_REGISTRY_SSL + "=" + useRegistrySsl +
396 "\n\t" + PropertyNames.SSL_CONFIG_FILE_NAME + "=" + sslConfigFileName +
397 "\n\t" + PropertyNames.SSL_ENABLED_CIPHER_SUITES + "=" +
398 enabledCipherSuites +
399 "\n\t" + PropertyNames.SSL_ENABLED_PROTOCOLS + "=" +
400 enabledProtocols +
401 "\n\t" + PropertyNames.SSL_NEED_CLIENT_AUTH + "=" +
402 sslNeedClientAuth +
403 "\n\t" + PropertyNames.USE_AUTHENTICATION + "=" +
404 useAuthentication +
405 (useAuthentication ? (loginConfigName == null ? ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
406 passwordFileName) : ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
407 loginConfigName)) : "\n\t" +
408 Agent.getText("jmxremote.ConnectorBootstrap.initialize.noAuthentication")) +
409 (useAuthentication ? ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
410 accessFileName) : "") +
411 "");
412 }
413
414 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
415 JMXConnectorServer cs = null;
416 JMXServiceURL url = null;
417 try {
418 final JMXConnectorServerData data = exportMBeanServer(
419 mbs, port, useSsl, useRegistrySsl,
420 sslConfigFileName, enabledCipherSuitesList,
421 enabledProtocolsList, sslNeedClientAuth,
422 useAuthentication, loginConfigName,
423 passwordFileName, accessFileName);
424 cs = data.jmxConnectorServer;
425 url = data.jmxRemoteURL;
426 log.config("initialize",
427 Agent.getText("jmxremote.ConnectorBootstrap.initialize.ready",
428 url.toString()));
429 } catch (Exception e) {
430 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
431 }
432 try {
433 // Export remote connector address and associated configuration
434 // properties to the instrumentation buffer.
435 Map<String, String> properties = new HashMap<String, String>();
436 properties.put("remoteAddress", url.toString());
437 properties.put("authenticate", useAuthenticationStr);
438 properties.put("ssl", useSslStr);
439 properties.put("sslRegistry", useRegistrySslStr);
440 properties.put("sslNeedClientAuth", sslNeedClientAuthStr);
441 ConnectorAddressLink.exportRemote(properties);
442 } catch (Exception e) {
443 // Remote connector server started but unable to export remote
444 // connector address and associated configuration properties to
445 // the instrumentation buffer - non-fatal error.
446 log.debug("initialize", e);
447 }
448 return cs;
449 }
450
451 /*
452 * Creates and starts a RMI Connector Server for "local" monitoring
453 * and management.
454 */
455 public static JMXConnectorServer startLocalConnectorServer() {
456 // Ensure cryptographically strong random number generater used
457 // to choose the object number - see java.rmi.server.ObjID
458 System.setProperty("java.rmi.server.randomIDs", "true");
459
460 // This RMI server should not keep the VM alive
461 Map<String, Object> env = new HashMap<String, Object>();
462 env.put(RMIExporter.EXPORTER_ATTRIBUTE, new PermanentExporter());
463
464 // The local connector server need only be available via the
465 // loopback connection.
466 String localhost = "localhost";
467 InetAddress lh = null;
468 try {
469 lh = InetAddress.getByName(localhost);
470 localhost = lh.getHostAddress();
471 } catch (UnknownHostException x) {
472 }
473
474 // localhost unknown or (somehow) didn't resolve to
475 // a loopback address.
476 if (lh == null || !lh.isLoopbackAddress()) {
477 localhost = "127.0.0.1";
478 }
479
480 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
481 try {
482 JMXServiceURL url = new JMXServiceURL("rmi", localhost, 0);
483 // Do we accept connections from local interfaces only?
484 Properties props = Agent.getManagementProperties();
485 if (props == null) {
486 props = new Properties();
487 }
488 String useLocalOnlyStr = props.getProperty(
489 PropertyNames.USE_LOCAL_ONLY, DefaultValues.USE_LOCAL_ONLY);
490 boolean useLocalOnly = Boolean.valueOf(useLocalOnlyStr).booleanValue();
491 if (useLocalOnly) {
492 env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
493 new LocalRMIServerSocketFactory());
494 }
495 JMXConnectorServer server =
496 JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
497 server.start();
498 return server;
499 } catch (Exception e) {
500 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
501 }
502 }
503
504 private static void checkPasswordFile(String passwordFileName) {
505 if (passwordFileName == null || passwordFileName.length() == 0) {
506 throw new AgentConfigurationError(PASSWORD_FILE_NOT_SET);
507 }
508 File file = new File(passwordFileName);
509 if (!file.exists()) {
510 throw new AgentConfigurationError(PASSWORD_FILE_NOT_FOUND, passwordFileName);
511 }
512
513 if (!file.canRead()) {
514 throw new AgentConfigurationError(PASSWORD_FILE_NOT_READABLE, passwordFileName);
515 }
516
517 FileSystem fs = FileSystem.open();
518 try {
519 if (fs.supportsFileSecurity(file)) {
520 if (!fs.isAccessUserOnly(file)) {
521 final String msg = Agent.getText("jmxremote.ConnectorBootstrap.initialize.password.readonly",
522 passwordFileName);
523 log.config("initialize", msg);
524 throw new AgentConfigurationError(PASSWORD_FILE_ACCESS_NOT_RESTRICTED,
525 passwordFileName);
526 }
527 }
528 } catch (IOException e) {
529 throw new AgentConfigurationError(PASSWORD_FILE_READ_FAILED,
530 e, passwordFileName);
531 }
532 }
533
534 private static void checkAccessFile(String accessFileName) {
535 if (accessFileName == null || accessFileName.length() == 0) {
536 throw new AgentConfigurationError(ACCESS_FILE_NOT_SET);
537 }
538 File file = new File(accessFileName);
539 if (!file.exists()) {
540 throw new AgentConfigurationError(ACCESS_FILE_NOT_FOUND, accessFileName);
541 }
542
543 if (!file.canRead()) {
544 throw new AgentConfigurationError(ACCESS_FILE_NOT_READABLE, accessFileName);
545 }
546 }
547
548 private static void checkRestrictedFile(String restrictedFileName) {
549 if (restrictedFileName == null || restrictedFileName.length() == 0) {
550 throw new AgentConfigurationError(FILE_NOT_SET);
551 }
552 File file = new File(restrictedFileName);
553 if (!file.exists()) {
554 throw new AgentConfigurationError(FILE_NOT_FOUND, restrictedFileName);
555 }
556 if (!file.canRead()) {
557 throw new AgentConfigurationError(FILE_NOT_READABLE, restrictedFileName);
558 }
559 FileSystem fs = FileSystem.open();
560 try {
561 if (fs.supportsFileSecurity(file)) {
562 if (!fs.isAccessUserOnly(file)) {
563 final String msg = Agent.getText(
564 "jmxremote.ConnectorBootstrap.initialize.file.readonly",
565 restrictedFileName);
566 log.config("initialize", msg);
567 throw new AgentConfigurationError(
568 FILE_ACCESS_NOT_RESTRICTED, restrictedFileName);
569 }
570 }
571 } catch (IOException e) {
572 throw new AgentConfigurationError(
573 FILE_READ_FAILED, e, restrictedFileName);
574 }
575 }
576
577 /**
578 * Compute the full path name for a default file.
579 * @param basename basename (with extension) of the default file.
580 * @return ${JRE}/lib/management/${basename}
581 **/
582 private static String getDefaultFileName(String basename) {
583 final String fileSeparator = File.separator;
584 return System.getProperty("java.home") + fileSeparator + "lib" +
585 fileSeparator + "management" + fileSeparator +
586 basename;
587 }
588
589 private static SslRMIServerSocketFactory createSslRMIServerSocketFactory(
590 String sslConfigFileName,
591 String[] enabledCipherSuites,
592 String[] enabledProtocols,
593 boolean sslNeedClientAuth) {
594 if (sslConfigFileName == null) {
595 return new SslRMIServerSocketFactory(
596 enabledCipherSuites,
597 enabledProtocols,
598 sslNeedClientAuth);
599 } else {
600 checkRestrictedFile(sslConfigFileName);
601 try {
602 // Load the SSL keystore properties from the config file
603 Properties p = new Properties();
604 InputStream in = new FileInputStream(sslConfigFileName);
605 try {
606 BufferedInputStream bin = new BufferedInputStream(in);
607 p.load(bin);
608 } finally {
609 in.close();
610 }
611 String keyStore =
612 p.getProperty("javax.net.ssl.keyStore");
613 String keyStorePassword =
614 p.getProperty("javax.net.ssl.keyStorePassword", "");
615 String trustStore =
616 p.getProperty("javax.net.ssl.trustStore");
617 String trustStorePassword =
618 p.getProperty("javax.net.ssl.trustStorePassword", "");
619
620 char[] keyStorePasswd = null;
621 if (keyStorePassword.length() != 0) {
622 keyStorePasswd = keyStorePassword.toCharArray();
623 }
624
625 char[] trustStorePasswd = null;
626 if (trustStorePassword.length() != 0) {
627 trustStorePasswd = trustStorePassword.toCharArray();
628 }
629
630 KeyStore ks = null;
631 if (keyStore != null) {
632 ks = KeyStore.getInstance(KeyStore.getDefaultType());
633 FileInputStream ksfis = new FileInputStream(keyStore);
634 try {
635 ks.load(ksfis, keyStorePasswd);
636 } finally {
637 ksfis.close();
638 }
639 }
640 KeyManagerFactory kmf = KeyManagerFactory.getInstance(
641 KeyManagerFactory.getDefaultAlgorithm());
642 kmf.init(ks, keyStorePasswd);
643
644 KeyStore ts = null;
645 if (trustStore != null) {
646 ts = KeyStore.getInstance(KeyStore.getDefaultType());
647 FileInputStream tsfis = new FileInputStream(trustStore);
648 try {
649 ts.load(tsfis, trustStorePasswd);
650 } finally {
651 tsfis.close();
652 }
653 }
654 TrustManagerFactory tmf = TrustManagerFactory.getInstance(
655 TrustManagerFactory.getDefaultAlgorithm());
656 tmf.init((KeyStore) ts);
657
658 SSLContext ctx = SSLContext.getInstance("SSL");
659 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
660
661 return new SslRMIServerSocketFactory(
662 ctx,
663 enabledCipherSuites,
664 enabledProtocols,
665 sslNeedClientAuth);
666 } catch (Exception e) {
667 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
668 }
669 }
670 }
671
672 private static JMXConnectorServerData exportMBeanServer(
673 MBeanServer mbs,
674 int port,
675 boolean useSsl,
676 boolean useRegistrySsl,
677 String sslConfigFileName,
678 String[] enabledCipherSuites,
679 String[] enabledProtocols,
680 boolean sslNeedClientAuth,
681 boolean useAuthentication,
682 String loginConfigName,
683 String passwordFileName,
684 String accessFileName)
685 throws IOException, MalformedURLException {
686
687 /* Make sure we use non-guessable RMI object IDs. Otherwise
688 * attackers could hijack open connections by guessing their
689 * IDs. */
690 System.setProperty("java.rmi.server.randomIDs", "true");
691
692 JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
693
694 Map<String, Object> env = new HashMap<String, Object>();
695
696 PermanentExporter exporter = new PermanentExporter();
697
698 env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
699
700 if (useAuthentication) {
701 if (loginConfigName != null) {
702 env.put("jmx.remote.x.login.config", loginConfigName);
703 }
704 if (passwordFileName != null) {
705 env.put("jmx.remote.x.password.file", passwordFileName);
706 }
707
708 env.put("jmx.remote.x.access.file", accessFileName);
709
710 if (env.get("jmx.remote.x.password.file") != null ||
711 env.get("jmx.remote.x.login.config") != null) {
712 env.put(JMXConnectorServer.AUTHENTICATOR,
713 new AccessFileCheckerAuthenticator(env));
714 }
715 }
716
717 RMIClientSocketFactory csf = null;
718 RMIServerSocketFactory ssf = null;
719
720 if (useSsl || useRegistrySsl) {
721 csf = new SslRMIClientSocketFactory();
722 ssf = createSslRMIServerSocketFactory(
723 sslConfigFileName, enabledCipherSuites,
724 enabledProtocols, sslNeedClientAuth);
725 }
726
727 if (useSsl) {
728 env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
729 csf);
730 env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
731 ssf);
732 }
733
734 JMXConnectorServer connServer = null;
735 try {
736 connServer =
737 JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
738 connServer.start();
739 } catch (IOException e) {
740 if (connServer == null) {
741 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
742 e, url.toString());
743 } else {
744 throw new AgentConfigurationError(CONNECTOR_SERVER_IO_ERROR,
745 e, connServer.getAddress().toString());
746 }
747 }
748
749 final Registry registry;
750 if (useRegistrySsl) {
751 registry =
752 new SingleEntryRegistry(port, csf, ssf,
753 "jmxrmi", exporter.firstExported);
754 } else {
755 registry =
756 new SingleEntryRegistry(port,
757 "jmxrmi", exporter.firstExported);
758 }
759
760 JMXServiceURL remoteURL = new JMXServiceURL(
761 "service:jmx:rmi:///jndi/rmi://" + url.getHost() + ":" +
762 ((UnicastRef) ((RemoteObject) registry).getRef()).getLiveRef().getPort() +
763 "/jmxrmi");
764
765 /* Our exporter remembers the first object it was asked to
766 export, which will be an RMIServerImpl appropriate for
767 publication in our special registry. We could
768 alternatively have constructed the RMIServerImpl explicitly
769 and then constructed an RMIConnectorServer passing it as a
770 parameter, but that's quite a bit more verbose and pulls in
771 lots of knowledge of the RMI connector. */
772
773 return new JMXConnectorServerData(connServer, remoteURL);
774 }
775
776 /**
777 * This class cannot be instantiated.
778 **/
779 private ConnectorBootstrap() {
780 }
781
782 private static final ClassLogger log =
783 new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
784 "ConnectorBootstrap");
785}