001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.jmxremoting; 018 019 import java.io.IOException; 020 import java.net.ServerSocket; 021 import java.rmi.server.RMIClientSocketFactory; 022 import java.rmi.server.RMIServerSocketFactory; 023 import java.util.HashMap; 024 import java.util.Map; 025 026 import javax.management.MBeanServer; 027 import javax.management.NotificationFilterSupport; 028 import javax.management.remote.JMXConnectionNotification; 029 import javax.management.remote.JMXConnectorServer; 030 import javax.management.remote.JMXConnectorServerFactory; 031 import javax.management.remote.JMXServiceURL; 032 import javax.management.remote.rmi.RMIConnectorServer; 033 import javax.net.ssl.KeyManagerFactory; 034 import javax.net.ssl.SSLServerSocket; 035 import javax.net.ssl.SSLServerSocketFactory; 036 import javax.rmi.ssl.SslRMIClientSocketFactory; 037 038 import org.apache.geronimo.gbean.GBeanInfo; 039 import org.apache.geronimo.gbean.GBeanInfoBuilder; 040 import org.apache.geronimo.management.geronimo.KeystoreManager; 041 import org.apache.geronimo.system.jmx.MBeanServerReference; 042 043 /** 044 * A secure (SSL/TLS) connector that supports the server side of JSR 160 JMX Remoting. 045 * 046 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 047 */ 048 public class JMXSecureConnector extends JMXConnector { 049 050 private KeystoreManager keystoreManager; 051 private String algorithm; 052 private String secureProtocol; 053 private String keyStore; 054 private String trustStore; 055 private String keyAlias; 056 private boolean clientAuth; 057 058 public JMXSecureConnector(MBeanServerReference mbeanServerReference, String objectName, ClassLoader classLoader) { 059 this(mbeanServerReference.getMBeanServer(), objectName, classLoader); 060 } 061 062 public JMXSecureConnector(MBeanServer mbeanServer, String objectName, ClassLoader classLoader) { 063 super(mbeanServer, objectName, classLoader); 064 } 065 066 public void setKeystoreManager(KeystoreManager keystoreManager) { 067 this.keystoreManager = keystoreManager; 068 } 069 070 public KeystoreManager getKeystoreManager() { 071 return this.keystoreManager; 072 } 073 074 public String getKeyStore() { 075 return this.keyStore; 076 } 077 078 public void setKeyStore(String keyStore) { 079 this.keyStore = keyStore; 080 } 081 082 public String getTrustStore() { 083 return this.trustStore; 084 } 085 086 public void setTrustStore(String trustStore) { 087 this.trustStore = trustStore; 088 } 089 090 public String getKeyAlias() { 091 return this.keyAlias; 092 } 093 094 public void setKeyAlias(String keyAlias) { 095 this.keyAlias = keyAlias; 096 } 097 098 public String getAlgorithm() { 099 return this.algorithm; 100 } 101 102 /** 103 * Algorithm to use. 104 * As different JVMs have different implementations available, the default algorithm can be used by supplying the value "Default". 105 * 106 * @param algorithm the algorithm to use, or "Default" to use the default from {@link javax.net.ssl.KeyManagerFactory#getDefaultAlgorithm()} 107 */ 108 public void setAlgorithm(String algorithm) { 109 if ("default".equalsIgnoreCase(algorithm)) { 110 this.algorithm = KeyManagerFactory.getDefaultAlgorithm(); 111 } else { 112 this.algorithm = algorithm; 113 } 114 } 115 116 public String getSecureProtocol() { 117 return this.secureProtocol; 118 } 119 120 public void setSecureProtocol(String secureProtocol) { 121 this.secureProtocol = secureProtocol; 122 } 123 124 public void setClientAuth(boolean clientAuth) { 125 this.clientAuth = clientAuth; 126 } 127 128 public boolean isClientAuth() { 129 return this.clientAuth; 130 } 131 132 public void doStart() throws Exception { 133 jmxServiceURL = new JMXServiceURL(protocol, host, port, urlPath); 134 Map env = new HashMap(); 135 Authenticator authenticator = null; 136 if (applicationConfigName != null) { 137 authenticator = new Authenticator(applicationConfigName, classLoader); 138 env.put(JMXConnectorServer.AUTHENTICATOR, authenticator); 139 } else { 140 log.warn("Starting unauthenticating JMXConnector for " + jmxServiceURL); 141 } 142 143 SSLServerSocketFactory sssf = keystoreManager.createSSLServerFactory(null, secureProtocol, algorithm, keyStore, keyAlias, trustStore, classLoader); 144 RMIServerSocketFactory rssf = new GeronimoSslRMIServerSocketFactory(sssf, clientAuth); 145 RMIClientSocketFactory rcsf = new SslRMIClientSocketFactory(); 146 env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, rssf); 147 env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, rcsf); 148 149 server = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, env, mbeanServer); 150 NotificationFilterSupport filter = new NotificationFilterSupport(); 151 filter.enableType(JMXConnectionNotification.OPENED); 152 filter.enableType(JMXConnectionNotification.CLOSED); 153 filter.enableType(JMXConnectionNotification.FAILED); 154 server.addNotificationListener(authenticator, filter, null); 155 server.start(); 156 log.debug("Started JMXConnector " + server.getAddress()); 157 } 158 159 private static class GeronimoSslRMIServerSocketFactory implements RMIServerSocketFactory { 160 private SSLServerSocketFactory sssf; 161 private boolean clientAuth; 162 163 public GeronimoSslRMIServerSocketFactory(SSLServerSocketFactory sssf, boolean clientAuth) { 164 this.sssf = sssf; 165 this.clientAuth = clientAuth; 166 } 167 168 public ServerSocket createServerSocket(int port) throws IOException { 169 SSLServerSocket ss = (SSLServerSocket) sssf.createServerSocket(port); 170 ss.setNeedClientAuth(clientAuth); 171 return ss; 172 } 173 } 174 175 public static final GBeanInfo GBEAN_INFO; 176 177 static { 178 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("JMX Secure Remoting Connector", JMXSecureConnector.class); 179 infoFactory.addReference("MBeanServerReference", MBeanServerReference.class); 180 infoFactory.addAttribute("objectName", String.class, false); 181 infoFactory.addAttribute("classLoader", ClassLoader.class, false); 182 183 infoFactory.addAttribute("protocol", String.class, true, true); 184 infoFactory.addAttribute("host", String.class, true, true); 185 infoFactory.addAttribute("port", int.class, true, true); 186 infoFactory.addAttribute("urlPath", String.class, true, true); 187 infoFactory.addAttribute("applicationConfigName", String.class, true, true); 188 189 infoFactory.addInterface(JMXConnectorInfo.class); 190 191 infoFactory.addReference("KeystoreManager", KeystoreManager.class); 192 infoFactory.addAttribute("algorithm", String.class, true, true); 193 infoFactory.addAttribute("secureProtocol", String.class, true, true); 194 infoFactory.addAttribute("keyStore", String.class, true, true); 195 infoFactory.addAttribute("keyAlias", String.class, true, true); 196 infoFactory.addAttribute("trustStore", String.class, true, true); 197 infoFactory.addAttribute("clientAuth", boolean.class, true, true); 198 199 infoFactory.setConstructor(new String[]{"MBeanServerReference", "objectName", "classLoader"}); 200 GBEAN_INFO = infoFactory.getBeanInfo(); 201 } 202 203 public static GBeanInfo getGBeanInfo() { 204 return GBEAN_INFO; 205 } 206 }