Author: remm
Date: Tue Jan 29 14:34:19 2019
New Revision: 1852458

URL: http://svn.apache.org/viewvc?rev=1852458&view=rev
Log:
Add full SSL configuration options to the JMX remote listener using the 
SSLHostConfig framework. Better configuration can be useful for cloud 
deployments, although raw JMX is often not the prefered option.

Modified:
    tomcat/trunk/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java
    tomcat/trunk/webapps/docs/changelog.xml
    tomcat/trunk/webapps/docs/config/listeners.xml

Modified: 
tomcat/trunk/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java?rev=1852458&r1=1852457&r2=1852458&view=diff
==============================================================================
--- 
tomcat/trunk/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java 
(original)
+++ 
tomcat/trunk/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java 
Tue Jan 29 14:34:19 2019
@@ -31,11 +31,7 @@ import java.rmi.registry.LocateRegistry;
 import java.rmi.registry.Registry;
 import java.rmi.server.RMIClientSocketFactory;
 import java.rmi.server.RMIServerSocketFactory;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 
 import javax.management.remote.JMXConnectorServer;
@@ -45,6 +41,7 @@ import javax.management.remote.rmi.RMIJR
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLServerSocket;
 import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
 import javax.rmi.ssl.SslRMIClientSocketFactory;
 import javax.rmi.ssl.SslRMIServerSocketFactory;
 
@@ -53,6 +50,9 @@ import org.apache.catalina.LifecycleEven
 import org.apache.catalina.LifecycleListener;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.net.SSLHostConfig;
+import org.apache.tomcat.util.net.SSLHostConfigCertificate;
+import org.apache.tomcat.util.net.jsse.JSSEUtil;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -62,7 +62,9 @@ import org.apache.tomcat.util.res.String
  * the listener. The remainder of the configuration is via the standard system
  * properties for configuring JMX.
  */
-public class JmxRemoteLifecycleListener implements LifecycleListener {
+public class JmxRemoteLifecycleListener extends SSLHostConfig implements 
LifecycleListener {
+
+    private static final long serialVersionUID = 1L;
 
     private static final Log log = 
LogFactory.getLog(JmxRemoteLifecycleListener.class);
 
@@ -74,9 +76,6 @@ public class JmxRemoteLifecycleListener
     protected int rmiServerPortPlatform = -1;
     protected boolean rmiRegistrySSL = true;
     protected boolean rmiServerSSL = true;
-    protected String ciphers[] = null;
-    protected String protocols[] = null;
-    protected boolean clientAuth = true;
     protected boolean authenticate = true;
     protected String passwordFile = null;
     protected String loginModuleName = null;
@@ -156,48 +155,138 @@ public class JmxRemoteLifecycleListener
         this.useLocalPorts = useLocalPorts;
     }
 
-    private void init() {
+    /**
+     * @return the rmiRegistrySSL
+     */
+    public boolean isRmiRegistrySSL() {
+        return rmiRegistrySSL;
+    }
+
+    /**
+     * @param rmiRegistrySSL the rmiRegistrySSL to set
+     */
+    public void setRmiRegistrySSL(boolean rmiRegistrySSL) {
+        this.rmiRegistrySSL = rmiRegistrySSL;
+    }
+
+    /**
+     * @return the rmiServerSSL
+     */
+    public boolean isRmiServerSSL() {
+        return rmiServerSSL;
+    }
+
+    /**
+     * @param rmiServerSSL the rmiServerSSL to set
+     */
+    public void setRmiServerSSL(boolean rmiServerSSL) {
+        this.rmiServerSSL = rmiServerSSL;
+    }
+
+    /**
+     * @return the authenticate
+     */
+    public boolean isAuthenticate() {
+        return authenticate;
+    }
+
+    /**
+     * @param authenticate the authenticate to set
+     */
+    public void setAuthenticate(boolean authenticate) {
+        this.authenticate = authenticate;
+    }
+
+    /**
+     * @return the passwordFile
+     */
+    public String getPasswordFile() {
+        return passwordFile;
+    }
+
+    /**
+     * @param passwordFile the passwordFile to set
+     */
+    public void setPasswordFile(String passwordFile) {
+        this.passwordFile = passwordFile;
+    }
+
+    /**
+     * @return the loginModuleName
+     */
+    public String getLoginModuleName() {
+        return loginModuleName;
+    }
+
+    /**
+     * @param loginModuleName the loginModuleName to set
+     */
+    public void setLoginModuleName(String loginModuleName) {
+        this.loginModuleName = loginModuleName;
+    }
+
+    /**
+     * @return the accessFile
+     */
+    public String getAccessFile() {
+        return accessFile;
+    }
+
+    /**
+     * @param accessFile the accessFile to set
+     */
+    public void setAccessFile(String accessFile) {
+        this.accessFile = accessFile;
+    }
+
+    protected void init() {
         // Get all the other parameters required from the standard system
         // properties. Only need to get the parameters that affect the creation
         // of the server port.
-        String rmiRegistrySSLValue = System.getProperty(
-                "com.sun.management.jmxremote.registry.ssl", "false");
-        rmiRegistrySSL = Boolean.parseBoolean(rmiRegistrySSLValue);
-
-        String rmiServerSSLValue = System.getProperty(
-                "com.sun.management.jmxremote.ssl", "true");
-        rmiServerSSL = Boolean.parseBoolean(rmiServerSSLValue);
+        String rmiRegistrySSLValue = 
System.getProperty("com.sun.management.jmxremote.registry.ssl");
+        if (rmiRegistrySSLValue != null) {
+            setRmiRegistrySSL(Boolean.parseBoolean(rmiRegistrySSLValue));
+        }
+
+        String rmiServerSSLValue = 
System.getProperty("com.sun.management.jmxremote.ssl");
+        if (rmiServerSSLValue != null) {
+            setRmiServerSSL(Boolean.parseBoolean(rmiServerSSLValue));
+        }
 
-        String protocolsValue = System.getProperty(
-                "com.sun.management.jmxremote.ssl.enabled.protocols");
+        String protocolsValue = 
System.getProperty("com.sun.management.jmxremote.ssl.enabled.protocols");
         if (protocolsValue != null) {
-            protocols = protocolsValue.split(",");
+            setEnabledProtocols(protocolsValue.split(","));
         }
 
-        String ciphersValue = System.getProperty(
-                "com.sun.management.jmxremote.ssl.enabled.cipher.suites");
+        String ciphersValue = 
System.getProperty("com.sun.management.jmxremote.ssl.enabled.cipher.suites");
         if (ciphersValue != null) {
-            ciphers = ciphersValue.split(",");
+            setCiphers(ciphersValue);
         }
 
-        String clientAuthValue = System.getProperty(
-                "com.sun.management.jmxremote.ssl.need.client.auth", "true");
-        clientAuth = Boolean.parseBoolean(clientAuthValue);
+        String clientAuthValue = 
System.getProperty("com.sun.management.jmxremote.ssl.need.client.auth");
+        if (clientAuthValue != null) {
+            setCertificateVerification(clientAuthValue);
+        }
 
-        String authenticateValue = System.getProperty(
-                "com.sun.management.jmxremote.authenticate", "true");
-        authenticate = Boolean.parseBoolean(authenticateValue);
+        String authenticateValue = 
System.getProperty("com.sun.management.jmxremote.authenticate");
+        if (authenticateValue != null) {
+            setAuthenticate(Boolean.parseBoolean(authenticateValue));
+        }
 
-        passwordFile = System.getProperty(
-                "com.sun.management.jmxremote.password.file",
-                "jmxremote.password");
+        String passwordFileValue = 
System.getProperty("com.sun.management.jmxremote.password.file");
+        if (passwordFileValue != null) {
+            setPasswordFile(passwordFileValue);
+        }
 
-        accessFile = System.getProperty(
-                "com.sun.management.jmxremote.access.file",
-                "jmxremote.access");
+        String accessFileValue = 
System.getProperty("com.sun.management.jmxremote.access.file");
+        if (accessFileValue != null) {
+            setAccessFile(accessFileValue);
+        }
 
-        loginModuleName = System.getProperty(
-                "com.sun.management.jmxremote.login.config");
+        String loginModuleNameValue = 
System.getProperty("com.sun.management.jmxremote.login.config");
+        if (loginModuleNameValue != null) {
+            setLoginModuleName(loginModuleNameValue);
+        }
     }
 
 
@@ -205,9 +294,30 @@ public class JmxRemoteLifecycleListener
     public void lifecycleEvent(LifecycleEvent event) {
         // When the server starts, configure JMX/RMI
         if (Lifecycle.START_EVENT.equals(event.getType())) {
-            // Configure using standard jmx system properties
+
+            // Configure using standard JMX system properties
             init();
 
+            SSLContext sslContext = null;
+            // Create SSL context if properties were set to define a 
certificate
+            if (getCertificates().size() > 0) {
+                SSLHostConfigCertificate certificate = 
getCertificates().iterator().next();
+                // This can only support JSSE
+                JSSEUtil sslUtil = new JSSEUtil(certificate);
+                try {
+                    sslContext = 
javax.net.ssl.SSLContext.getInstance(getSslProtocol());
+                    setEnabledProtocols(sslUtil.getEnabledProtocols());
+                    setEnabledCiphers(sslUtil.getEnabledCiphers());
+                    sslContext.init(sslUtil.getKeyManagers(), 
sslUtil.getTrustManagers(), null);
+                    SSLSessionContext sessionContext = 
sslContext.getServerSessionContext();
+                    if (sessionContext != null) {
+                        sslUtil.configureSessionContext(sessionContext);
+                    }
+                } catch (Exception e) {
+                    
log.error(sm.getString("jmxRemoteLifecycleListener.invalidSSLConfiguration"), 
e);
+                }
+            }
+
             // Prevent an attacker guessing the RMI object ID
             System.setProperty("java.rmi.server.randomIDs", "true");
 
@@ -224,11 +334,14 @@ public class JmxRemoteLifecycleListener
             if (rmiRegistrySSL) {
                 registryCsf = new SslRMIClientSocketFactory();
                 if (rmiBindAddress == null) {
-                    registrySsf = new SslRMIServerSocketFactory(
-                            ciphers, protocols, clientAuth);
+                    registrySsf = new SslRMIServerSocketFactory(sslContext,
+                            getEnabledCiphers(), getEnabledProtocols(),
+                            getCertificateVerification() == 
CertificateVerification.REQUIRED);
                 } else {
-                    registrySsf = new SslRmiServerBindSocketFactory(
-                            ciphers, protocols, clientAuth, rmiBindAddress);
+                    registrySsf = new SslRmiServerBindSocketFactory(sslContext,
+                            getEnabledCiphers(), getEnabledProtocols(),
+                            getCertificateVerification() == 
CertificateVerification.REQUIRED,
+                            rmiBindAddress);
                 }
             } else {
                 if (rmiBindAddress != null) {
@@ -240,11 +353,14 @@ public class JmxRemoteLifecycleListener
             if (rmiServerSSL) {
                 serverCsf = new SslRMIClientSocketFactory();
                 if (rmiBindAddress == null) {
-                    serverSsf = new SslRMIServerSocketFactory(
-                            ciphers, protocols, clientAuth);
+                    serverSsf = new SslRMIServerSocketFactory(sslContext,
+                            getEnabledCiphers(), getEnabledProtocols(),
+                            getCertificateVerification() == 
CertificateVerification.REQUIRED);
                 } else {
-                    serverSsf = new SslRmiServerBindSocketFactory(
-                            ciphers, protocols, clientAuth, rmiBindAddress);
+                    serverSsf = new SslRmiServerBindSocketFactory(sslContext,
+                            getEnabledCiphers(), getEnabledProtocols(),
+                            getCertificateVerification() == 
CertificateVerification.REQUIRED,
+                            rmiBindAddress);
                 }
             } else {
                 if (rmiBindAddress != null) {
@@ -410,34 +526,13 @@ public class JmxRemoteLifecycleListener
 
     public static class SslRmiServerBindSocketFactory extends 
SslRMIServerSocketFactory {
 
-        private static final SSLServerSocketFactory sslServerSocketFactory;
-        private static final String[] defaultProtocols;
-
-        static {
-            SSLContext sslContext;
-            try {
-                sslContext = SSLContext.getDefault();
-            } catch (NoSuchAlgorithmException e) {
-                // Can't continue. Force a failure.
-                throw new IllegalStateException(e);
-            }
-            sslServerSocketFactory = sslContext.getServerSocketFactory();
-            String[] protocols = 
sslContext.getDefaultSSLParameters().getProtocols();
-            List<String> filteredProtocols = new ArrayList<>(protocols.length);
-            for (String protocol : protocols) {
-                if (protocol.toUpperCase(Locale.ENGLISH).contains("SSL")) {
-                    continue;
-                }
-                filteredProtocols.add(protocol);
-            }
-            defaultProtocols = filteredProtocols.toArray(new 
String[filteredProtocols.size()]);
-        }
-
         private final InetAddress bindAddress;
+        private final SSLContext sslContext;
 
-        public SslRmiServerBindSocketFactory(String[] enabledCipherSuites,
+        public SslRmiServerBindSocketFactory(SSLContext sslContext, String[] 
enabledCipherSuites,
                 String[] enabledProtocols, boolean needClientAuth, String 
address) {
-            super(enabledCipherSuites, enabledProtocols, needClientAuth);
+            super(sslContext, enabledCipherSuites, enabledProtocols, 
needClientAuth);
+            this.sslContext = sslContext;
             InetAddress bindAddress = null;
             try {
                 bindAddress = InetAddress.getByName(address);
@@ -451,15 +546,16 @@ public class JmxRemoteLifecycleListener
         }
 
         @Override
-        public ServerSocket createServerSocket(int port) throws IOException  {
+        public ServerSocket createServerSocket(int port) throws IOException {
+            SSLServerSocketFactory sslServerSocketFactory = (sslContext == 
null)
+                    ? (SSLServerSocketFactory) 
SSLServerSocketFactory.getDefault()
+                    : sslContext.getServerSocketFactory();
             SSLServerSocket sslServerSocket =
                     (SSLServerSocket) 
sslServerSocketFactory.createServerSocket(port, 0, bindAddress);
             if (getEnabledCipherSuites() != null) {
                 
sslServerSocket.setEnabledCipherSuites(getEnabledCipherSuites());
             }
-            if (getEnabledProtocols() == null) {
-                sslServerSocket.setEnabledProtocols(defaultProtocols);
-            } else {
+            if (getEnabledProtocols() != null) {
                 sslServerSocket.setEnabledProtocols(getEnabledProtocols());
             }
             sslServerSocket.setNeedClientAuth(getNeedClientAuth());

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1852458&r1=1852457&r2=1852458&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Tue Jan 29 14:34:19 2019
@@ -130,6 +130,10 @@
         application class loading when running under a
         <code>SecurityManager</code>. (markt)
       </fix>
+      <update>
+        Add SSL configuration options to the JMX remote listener using the
+        <code>SSLHostConfig</code> framework. (remm)
+      </update>
     </changelog>
   </subsection>
   <subsection name="Coyote">

Modified: tomcat/trunk/webapps/docs/config/listeners.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/listeners.xml?rev=1852458&r1=1852457&r2=1852458&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/listeners.xml (original)
+++ tomcat/trunk/webapps/docs/config/listeners.xml Tue Jan 29 14:34:19 2019
@@ -509,8 +509,16 @@
     <p>The <strong>JMX Remote Lifecycle Listener</strong> fixes the ports used 
by
     the JMX/RMI Server making things much simpler if you need to connect
     jconsole or a similar tool to a remote Tomcat instance that is running
-    behind a firewall. Only these ports are configured via the listener. The
-    remainder of the configuration is via the standard system properties for
+    behind a firewall.</p>
+
+    <p>Note: The SSL configuration can be done with attributes identical to 
those
+    of <a href="http.html#SSL_Support_-_SSLHostConfig">SSLHostConfig</a> and 
the
+    properties of the default certificate as defined for
+    <a href="http.html#SSL_Support_-_Certificate">SSLHostConfigCertificate</a>.
+    This will create a JSSE SSLContext which will be given to the JMX/RMI 
registry
+    when creating the server socket.</p>
+
+    <p>The remainder of the configuration is via the standard system 
properties for
     configuring JMX. For further information on configuring JMX see
     <a 
href="http://docs.oracle.com/javase/6/docs/technotes/guides/management/agent.html";>
     Monitoring and Management Using JMX</a> included with the Java SDK
@@ -520,7 +528,7 @@
     element.</p>
 
     <p>The following additional attributes are supported by the <strong>JMX 
Remote
-    Lifecycle Listener</strong>:</p>
+    Lifecycle Listener</strong>, in addition to the SSL related attributes:</p>
 
     <attributes>
 
@@ -569,6 +577,13 @@
     <code>letmein</code>.
     </p>
 
+    <h3>SSL configurations</h3>
+
+    <p>A certificate can be defined for the server using a keystore:</p>
+  <source><![CDATA[  <Listener 
className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
+               rmiRegistryPortPlatform="10001" rmiServerPortPlatform="10002"
+               certificateKeystoreFile="${catalina.home}/conf/mykeystore.jks" 
/>]]></source>
+
     <h3>Using JAAS</h3>
 
     <p>If we use the following system properties instead:</p>



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to