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 }