You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2017/09/15 20:11:53 UTC

svn commit: r1808482 - in /tomcat/trunk: java/org/apache/coyote/ java/org/apache/tomcat/util/net/ webapps/docs/

Author: markt
Date: Fri Sep 15 20:11:53 2017
New Revision: 1808482

URL: http://svn.apache.org/viewvc?rev=1808482&view=rev
Log:
Allow runtime updates to the current SSLHostConfigs.
Move JMX registration to the Endpoint to make it easirt to keep JMX registration in sync with runtime changes.
Protect against removing the default while running

Modified:
    tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java
    tomcat/trunk/java/org/apache/coyote/LocalStrings.properties
    tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java
    tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties
    tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfig.java
    tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java?rev=1808482&r1=1808481&r2=1808482&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java Fri Sep 15 20:11:53 2017
@@ -19,7 +19,6 @@ package org.apache.coyote;
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -43,8 +42,6 @@ import org.apache.tomcat.util.collection
 import org.apache.tomcat.util.modeler.Registry;
 import org.apache.tomcat.util.net.AbstractEndpoint;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler;
-import org.apache.tomcat.util.net.SSLHostConfig;
-import org.apache.tomcat.util.net.SSLHostConfigCertificate;
 import org.apache.tomcat.util.net.SocketEvent;
 import org.apache.tomcat.util.net.SocketWrapperBase;
 import org.apache.tomcat.util.res.StringManager;
@@ -72,16 +69,6 @@ public abstract class AbstractProtocol<S
 
 
     /**
-     * Name of MBean for the ThreadPool.
-     */
-    protected ObjectName tpOname = null;
-
-
-    private Set<ObjectName> sslOnames = new HashSet<>();
-    private Set<ObjectName> sslCertOnames = new HashSet<>();
-
-
-    /**
      * Unique ID for this connector. Only used if the connector is configured
      * to use a random port as the port will change if stop(), start() is
      * called.
@@ -541,36 +528,14 @@ public abstract class AbstractProtocol<S
         }
 
         if (this.domain != null) {
-            try {
-                tpOname = new ObjectName(domain + ":type=ThreadPool,name=" + getName());
-                Registry.getRegistry(null, null).registerComponent(endpoint, tpOname, null);
-            } catch (Exception e) {
-                getLog().error(sm.getString( "abstractProtocolHandler.mbeanRegistrationFailed",
-                        tpOname, getName()), e);
-            }
             rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
             Registry.getRegistry(null, null).registerComponent(
                     getHandler().getGlobal(), rgOname, null);
-
-            for (SSLHostConfig sslHostConfig : getEndpoint().findSslHostConfigs()) {
-                ObjectName sslOname = new ObjectName(domain + ":type=SSLHostConfig,ThreadPool=" +
-                        getName() + ",name=" + ObjectName.quote(sslHostConfig.getHostName()));
-                Registry.getRegistry(null, null).registerComponent(sslHostConfig, sslOname, null);
-                sslOnames.add(sslOname);
-                for (SSLHostConfigCertificate sslHostConfigCert : sslHostConfig.getCertificates()) {
-                    ObjectName sslCertOname = new ObjectName(domain +
-                            ":type=SSLHostConfigCertificate,ThreadPool=" + getName() +
-                            ",Host=" + ObjectName.quote(sslHostConfig.getHostName()) +
-                            ",name=" + sslHostConfigCert.getType());
-                    Registry.getRegistry(null, null).registerComponent(
-                            sslHostConfigCert, sslCertOname, null);
-                    sslCertOnames.add(sslCertOname);
-                }
-            }
         }
 
         String endpointName = getName();
         endpoint.setName(endpointName.substring(1, endpointName.length()-1));
+        endpoint.setDomain(domain);
 
         endpoint.init();
     }
@@ -659,18 +624,9 @@ public abstract class AbstractProtocol<S
                 }
             }
 
-            if (tpOname != null) {
-                Registry.getRegistry(null, null).unregisterComponent(tpOname);
-            }
             if (rgOname != null) {
                 Registry.getRegistry(null, null).unregisterComponent(rgOname);
             }
-            for (ObjectName oname : sslOnames) {
-                Registry.getRegistry(null, null).unregisterComponent(oname);
-            }
-            for (ObjectName oname : sslCertOnames) {
-                Registry.getRegistry(null, null).unregisterComponent(oname);
-            }
         }
     }
 

Modified: tomcat/trunk/java/org/apache/coyote/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/LocalStrings.properties?rev=1808482&r1=1808481&r2=1808482&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/coyote/LocalStrings.properties Fri Sep 15 20:11:53 2017
@@ -34,7 +34,6 @@ abstractProtocol.mbeanDeregistrationFail
 abstractProtocolHandler.getAttribute=Get attribute [{0}] with value [{1}]
 abstractProtocolHandler.setAttribute=Set attribute [{0}] with value [{1}]
 abstractProtocolHandler.init=Initializing ProtocolHandler [{0}]
-abstractProtocolHandler.mbeanRegistrationFailed=Failed to register MBean [{0}] for ProtocolHandler [{1}]
 abstractProtocolHandler.start=Starting ProtocolHandler [{0}]
 abstractProtocolHandler.pause=Pausing ProtocolHandler [{0}]
 abstractProtocolHandler.resume=Resuming ProtocolHandler [{0}]

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java?rev=1808482&r1=1808481&r2=1808482&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java Fri Sep 15 20:11:53 2017
@@ -33,10 +33,14 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
 import org.apache.juli.logging.Log;
 import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.IntrospectionUtils;
 import org.apache.tomcat.util.collections.SynchronizedStack;
+import org.apache.tomcat.util.modeler.Registry;
 import org.apache.tomcat.util.net.Acceptor.AcceptorState;
 import org.apache.tomcat.util.res.StringManager;
 import org.apache.tomcat.util.threads.LimitLatch;
@@ -170,6 +174,8 @@ public abstract class AbstractEndpoint<S
      */
     protected SynchronizedStack<SocketProcessorBase<S>> processorCache;
 
+    private ObjectName oname = null;
+
     // ----------------------------------------------------------------- Properties
 
     private String defaultSSLHostConfigName = SSLHostConfig.DEFAULT_SSL_HOST_NAME;
@@ -182,7 +188,33 @@ public abstract class AbstractEndpoint<S
 
 
     protected ConcurrentMap<String,SSLHostConfig> sslHostConfigs = new ConcurrentHashMap<>();
+    /**
+     * Add the given SSL Host configuration.
+     *
+     * @param sslHostConfig The configuration to add
+     *
+     * @throws IllegalArgumentException If the host name is not valid or if a
+     *                                  configuration has already been provided
+     *                                  for that host
+     */
     public void addSslHostConfig(SSLHostConfig sslHostConfig) throws IllegalArgumentException {
+        addSslHostConfig(sslHostConfig, false);
+    }
+    /**
+     * Add the given SSL Host configuration, optionally replacing the existing
+     * configuration for the given host.
+     *
+     * @param sslHostConfig The configuration to add
+     * @param replace       If {@code true} replacement of an existing
+     *                      configuration is permitted, otherwise any such
+     *                      attempted replacement will trigger an exception
+     *
+     * @throws IllegalArgumentException If the host name is not valid or if a
+     *                                  configuration has already been provided
+     *                                  for that host and replacement is not
+     *                                  allowed
+     */
+    public void addSslHostConfig(SSLHostConfig sslHostConfig, boolean replace) throws IllegalArgumentException {
         String key = sslHostConfig.getHostName();
         if (key == null || key.length() == 0) {
             throw new IllegalArgumentException(sm.getString("endpoint.noSslHostName"));
@@ -195,10 +227,69 @@ public abstract class AbstractEndpoint<S
                 throw new IllegalArgumentException(e);
             }
         }
-        SSLHostConfig duplicate = sslHostConfigs.putIfAbsent(key, sslHostConfig);
-        if (duplicate != null) {
-            releaseSSLContext(sslHostConfig);
-            throw new IllegalArgumentException(sm.getString("endpoint.duplicateSslHostName", key));
+        if (replace) {
+            SSLHostConfig previous = sslHostConfigs.put(key, sslHostConfig);
+            if (previous != null) {
+                unregisterJmx(sslHostConfig);
+            }
+            registerJmx(sslHostConfig);
+
+            // Do not release any SSLContexts associated with a replaced
+            // SSLHostConfig. They may still be in used by existing connections
+            // and releasing them would break the connection at best. Let GC
+            // handle the clean up.
+        } else {
+            SSLHostConfig duplicate = sslHostConfigs.putIfAbsent(key, sslHostConfig);
+            if (duplicate != null) {
+                releaseSSLContext(sslHostConfig);
+                throw new IllegalArgumentException(sm.getString("endpoint.duplicateSslHostName", key));
+            }
+            registerJmx(sslHostConfig);
+        }
+    }
+    /**
+     * Removes the SSL host configuration for the given host name, if such a
+     * configuration exists.
+     *
+     * @param hostName  The host name associated with the SSL host configuration
+     *                  to remove
+     *
+     * @return  The SSL host configuration that was removed, if any
+     */
+    public SSLHostConfig removeSslHostConfig(String hostName) {
+        // Host names are case insensitive
+        if (hostName != null && hostName.equalsIgnoreCase(getDefaultSSLHostConfigName())) {
+            throw new IllegalArgumentException(
+                    sm.getString("endpoint.removeDefaultSslHostConfig", hostName));
+        }
+        SSLHostConfig sslHostConfig = sslHostConfigs.remove(hostName);
+        unregisterJmx(sslHostConfig);
+        return sslHostConfig;
+    }
+    /**
+     * Re-read the configuration files for the SSL host and replace the existing
+     * SSL configuration with the updated settings. Note this replacement will
+     * happen even if the settings remain unchanged.
+     *
+     * @param hostName The SSL host for which the configuration should be
+     *                 reloaded. This must match a current SSL host
+     */
+    public void reloadSslHostConfig(String hostName) {
+        SSLHostConfig sslHostConfig = sslHostConfigs.get(hostName);
+        if (sslHostConfig == null) {
+            throw new IllegalArgumentException(
+                    sm.getString("endpoint.unknownSslHostName", hostName));
+        }
+        addSslHostConfig(sslHostConfig, true);
+    }
+    /**
+     * Re-read the configuration files for all SSL hosts and replace the
+     * existing SSL configuration with the updated settings. Note this
+     * replacement will happen even if the settings remain unchanged.
+     */
+    public void reloadSslHostConfigs() {
+        for (String hostName : sslHostConfigs.keySet()) {
+            reloadSslHostConfig(hostName);
         }
     }
     public SSLHostConfig[] findSslHostConfigs() {
@@ -565,6 +656,15 @@ public abstract class AbstractEndpoint<S
     public void setName(String name) { this.name = name; }
     public String getName() { return name; }
 
+
+    /**
+     * Name of domain to use for JMX registration.
+     */
+    private String domain;
+    public void setDomain(String domain) { this.domain = domain; }
+    public String getDomain() { return domain; }
+
+
     /**
      * The default is true - the created threads will be
      *  in daemon mode. If set to false, the control thread
@@ -939,6 +1039,62 @@ public abstract class AbstractEndpoint<S
             bind();
             bindState = BindState.BOUND_ON_INIT;
         }
+        if (this.domain != null) {
+            // Register endpoint (as ThreadPool - historical name)
+            oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
+            Registry.getRegistry(null, null).registerComponent(this, oname, null);
+
+            for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
+                registerJmx(sslHostConfig);
+            }
+        }
+    }
+
+
+    private void registerJmx(SSLHostConfig sslHostConfig) {
+        ObjectName sslOname = null;
+        try {
+            sslOname = new ObjectName(domain + ":type=SSLHostConfig,ThreadPool=" +
+                    getName() + ",name=" + ObjectName.quote(sslHostConfig.getHostName()));
+            sslHostConfig.setObjectName(sslOname);
+            try {
+                Registry.getRegistry(null, null).registerComponent(sslHostConfig, sslOname, null);
+            } catch (Exception e) {
+                getLog().warn(sm.getString("endpoint.jmxRegistrationFailed", sslOname), e);
+            }
+        } catch (MalformedObjectNameException e) {
+            getLog().warn(sm.getString("endpoint.invalidJmxNameSslHost",
+                    sslHostConfig.getHostName()), e);
+        }
+
+        for (SSLHostConfigCertificate sslHostConfigCert : sslHostConfig.getCertificates()) {
+            ObjectName sslCertOname = null;
+            try {
+                sslCertOname = new ObjectName(domain +
+                        ":type=SSLHostConfigCertificate,ThreadPool=" + getName() +
+                        ",Host=" + ObjectName.quote(sslHostConfig.getHostName()) +
+                        ",name=" + sslHostConfigCert.getType());
+                sslHostConfigCert.setObjectName(sslCertOname);
+                try {
+                    Registry.getRegistry(null, null).registerComponent(
+                            sslHostConfigCert, sslCertOname, null);
+                } catch (Exception e) {
+                    getLog().warn(sm.getString("endpoint.jmxRegistrationFailed", sslCertOname), e);
+                }
+            } catch (MalformedObjectNameException e) {
+                getLog().warn(sm.getString("endpoint.invalidJmxNameSslHostCert",
+                        sslHostConfig.getHostName(), sslHostConfigCert.getType()), e);
+            }
+        }
+    }
+
+
+    private void unregisterJmx(SSLHostConfig sslHostConfig) {
+        Registry registry = Registry.getRegistry(null, null);
+        registry.unregisterComponent(sslHostConfig.getObjectName());
+        for (SSLHostConfigCertificate sslHostConfigCert : sslHostConfig.getCertificates()) {
+            registry.unregisterComponent(sslHostConfigCert.getObjectName());
+        }
     }
 
 
@@ -1004,8 +1160,14 @@ public abstract class AbstractEndpoint<S
             unbind();
             bindState = BindState.UNBOUND;
         }
+        Registry registry = Registry.getRegistry(null, null);
+        registry.unregisterComponent(oname);
+        for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
+            unregisterJmx(sslHostConfig);
+        }
     }
 
+
     protected abstract Log getLog();
 
     protected LimitLatch initializeConnectionLatch() {

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties?rev=1808482&r1=1808481&r2=1808482&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties Fri Sep 15 20:11:53 2017
@@ -49,6 +49,9 @@ endpoint.getAttribute=[{0}] is [{1}]
 endpoint.init.bind=Socket bind failed: [{0}] [{1}]
 endpoint.init.listen=Socket listen failed: [{0}] [{1}]
 endpoint.init.notavail=APR not available
+endpoint.invalidJmxNameSslHost=Unable to generate a valid JMX object name for the SSLHostConfig associated with host [{0}]
+endpoint.invalidJmxNameSslHostCert=Unable to generate a valid JMX object name for the SSLHostConfigCertificate associated with host [{0}] and certificate type [{1}]
+endpoint.jmxRegistrationFailed=Failed to register the JMX object with name [{0}]
 endpoint.launch.fail=Failed to launch new runnable
 endpoint.noSslHostConfig=No SSLHostConfig element was found with the hostName [{0}] to match the defaultSSLHostConfigName for the connector [{1}]
 endpoint.noSslHostName=No host name was provided for the SSL host configuration
@@ -58,10 +61,12 @@ endpoint.poll.fail=Critical poller failu
 endpoint.poll.error=Unexpected poller error
 endpoint.process.fail=Error allocating socket processor
 endpoint.processing.fail=Error running socket processor
+endpoint.removeDefaultSslHostConfig=The default SSLHostConfig (named [{0}]) may not be removed
 endpoint.sendfile.error=Unexpected sendfile error
 endpoint.sendfile.addfail=Sendfile failure: [{0}] [{1}]
 endpoint.setAttribute=Set [{0}] to [{1}]
 endpoint.timeout.err=Error processing socket timeout
+endpoint.unknownSslHostName=The SSL host name [{0}] is not recognised for this endpoint
 endpoint.apr.failSslContextMake=Unable to create SSLContext. Check that SSLEngine is enabled in the AprLifecycleListener, the AprLifecycleListener has initialised correctly and that a valid SSLProtocol has been specified
 endpoint.apr.invalidSslProtocol=An invalid value [{0}] was provided for the SSLProtocol attribute
 endpoint.apr.maxConnections.running=The APR endpoint does not support the setting of maxConnections while it is running. The existing value of [{0}] will continue to be used.

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfig.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfig.java?rev=1808482&r1=1808481&r2=1808482&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfig.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfig.java Fri Sep 15 20:11:53 2017
@@ -28,6 +28,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import javax.management.ObjectName;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.TrustManagerFactory;
 
@@ -78,6 +79,7 @@ public class SSLHostConfig implements Se
     // Internal
     private String[] enabledCiphers;
     private String[] enabledProtocols;
+    private ObjectName oname;
     // Nested
     private SSLHostConfigCertificate defaultCertificate = null;
     private Set<SSLHostConfigCertificate> certificates = new HashSet<>(4);
@@ -218,6 +220,16 @@ public class SSLHostConfig implements Se
     }
 
 
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+
+    public void setObjectName(ObjectName oname) {
+        this.oname = oname;
+    }
+
+
     // ------------------------------------------- Nested configuration elements
 
     private void registerDefaultCertificate() {

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java?rev=1808482&r1=1808481&r2=1808482&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SSLHostConfigCertificate.java Fri Sep 15 20:11:53 2017
@@ -22,6 +22,8 @@ import java.security.KeyStore;
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.management.ObjectName;
+
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.net.openssl.ciphers.Authentication;
@@ -41,6 +43,9 @@ public class SSLHostConfigCertificate im
     static final String DEFAULT_KEYSTORE_TYPE =
             System.getProperty("javax.net.ssl.keyStoreType", "JKS");
 
+    // Internal
+    private ObjectName oname;
+
     // OpenSSL can handle multiple certs in a single config so the reference to
     // the context is at the virtual host level. JSSE can't so the reference is
     // held here on the certificate.
@@ -92,6 +97,18 @@ public class SSLHostConfigCertificate im
     }
 
 
+    // Internal
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+
+    public void setObjectName(ObjectName oname) {
+        this.oname = oname;
+    }
+
+
     // Common
 
     public Type getType() {

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1808482&r1=1808481&r2=1808482&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Sep 15 20:11:53 2017
@@ -45,6 +45,15 @@
   issues do not "pop up" wrt. others).
 -->
 <section name="Tomcat 9.0.0.M28 (markt)" rtext="in development">
+  <subsection name="Coyote">
+    <changelog>
+      <add>
+        <bug>60762</bug>: Add the ability to make changes to the TLS
+        configuration of a connector at runtime without having to restart the
+        Connector. (markt)
+      </add>
+    </changelog>
+  </subsection>
 </section>
 <section name="Tomcat 9.0.0.M27 (markt)" rtext="release in progress">
   <subsection name="Catalina">



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org