accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From els...@apache.org
Subject [3/6] accumulo git commit: ACCUMULO-3317 Restrict Jetty secure protocol to TLS by default.
Date Fri, 07 Nov 2014 23:31:17 GMT
ACCUMULO-3317 Restrict Jetty secure protocol to TLS by default.

Warn if the user configures SSL instead of the default TLS


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/7789b200
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/7789b200
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/7789b200

Branch: refs/heads/master
Commit: 7789b200d84505b376955352fabd03d8a73b8cdf
Parents: 2deabd3
Author: Josh Elser <elserj@apache.org>
Authored: Fri Nov 7 17:17:32 2014 -0500
Committer: Josh Elser <elserj@apache.org>
Committed: Fri Nov 7 17:53:40 2014 -0500

----------------------------------------------------------------------
 .../org/apache/accumulo/core/conf/Property.java |  75 ++++++------
 .../org/apache/accumulo/server/Accumulo.java    |  49 +++++---
 .../accumulo/server/util/EmbeddedWebServer.java | 118 ++++++++++++++++---
 3 files changed, 172 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/7789b200/core/src/main/java/org/apache/accumulo/core/conf/Property.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/conf/Property.java b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
index 86f116b..1c0de78 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/Property.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
@@ -57,7 +57,7 @@ public enum Property {
       "The URL Accumulo should use to connect to DFS. If this is blank, Accumulo will obtain
this information from the Hadoop configuration", true, false),
   CRYPTO_DEFAULT_KEY_STRATEGY_KEY_LOCATION("crypto.default.key.strategy.key.location", "/accumulo/crypto/secret/keyEncryptionKey",
PropertyType.ABSOLUTEPATH,
       "The absolute path of where to store the key encryption key within HDFS.", true, false),
-  
+
   // instance properties (must be the same for every node in an instance)
   INSTANCE_PREFIX("instance.", null, PropertyType.PREFIX,
       "Properties in this category must be consistent throughout a cloud. This is enforced
and servers won't be able to communicate if these differ."),
@@ -78,7 +78,7 @@ public enum Property {
       "The authorizor class that accumulo will use to determine what labels a user has privilege
to see"),
   INSTANCE_SECURITY_PERMISSION_HANDLER("instance.security.permissionHandler", "org.apache.accumulo.server.security.handler.ZKPermHandler",
       PropertyType.CLASSNAME, "The permission handler class that accumulo will use to determine
if a user has privilege to perform an action"),
-  
+
   // general properties
   GENERAL_PREFIX("general.", null, PropertyType.PREFIX,
       "Properties in this category affect the behavior of accumulo overall, but do not have
to be consistent throughout a cloud."),
@@ -93,7 +93,7 @@ public enum Property {
   GENERAL_KERBEROS_PRINCIPAL("general.kerberos.principal", "", PropertyType.STRING, "Name
of the kerberos principal to use. _HOST will automatically be "
       + "replaced by the machines hostname in the hostname portion of the principal. Leave
blank if not using kerberoized hdfs"),
   GENERAL_MAX_MESSAGE_SIZE("tserver.server.message.size.max", "1G", PropertyType.MEMORY,
"The maximum size of a message that can be sent to a tablet server."),
-  
+
   // properties that are specific to master server behavior
   MASTER_PREFIX("master.", null, PropertyType.PREFIX, "Properties in this category affect
the behavior of the master server"),
   MASTER_CLIENTPORT("master.port.client", "9999", PropertyType.PORT, "The port used for handling
client connections on the master"),
@@ -114,7 +114,7 @@ public enum Property {
       "A class that implements a mechansim to steal write access to a file"),
   MASTER_FATE_THREADPOOL_SIZE("master.fate.threadpool.size", "4", PropertyType.COUNT,
       "The number of threads used to run FAult-Tolerant Executions.  These are primarily
table operations like merge."),
-  
+
   // properties that are specific to tablet server behavior
   TSERV_PREFIX("tserver.", null, PropertyType.PREFIX, "Properties in this category affect
the behavior of the tablet servers"),
   TSERV_CLIENT_TIMEOUT("tserver.client.timeout", "3s", PropertyType.TIMEDURATION, "Time to
wait for clients to continue scans before closing a session."),
@@ -209,7 +209,7 @@ public enum Property {
       "resiliency in the face of unexpected power outages, at the cost of speed. If method
is not available, the legacy 'sync' method " +
       "will be used to ensure backwards compatibility with older Hadoop versions. A value
of 'hflush' is the alternative to the default value " +
       "of 'hsync' which will result in faster writes, but with less durability"),
-  
+
   // properties that are specific to logger server behavior
   LOGGER_PREFIX("logger.", null, PropertyType.PREFIX, "Properties in this category affect
the behavior of the write-ahead logger servers"),
   LOGGER_DIR("logger.dir.walog", "walogs", PropertyType.PATH,
@@ -225,7 +225,7 @@ public enum Property {
   GC_PORT("gc.port.client", "50091", PropertyType.PORT, "The listening port for the garbage
collector's monitor service"),
   GC_DELETE_THREADS("gc.threads.delete", "16", PropertyType.COUNT, "The number of threads
used to delete files"),
   GC_TRASH_IGNORE("gc.trash.ignore", "false", PropertyType.BOOLEAN, "Do not use the Trash,
even if it is configured"),
-  
+
   // properties that are specific to the monitor server behavior
   MONITOR_PREFIX("monitor.", null, PropertyType.PREFIX, "Properties in this category affect
the behavior of the monitor web server."),
   MONITOR_PORT("monitor.port.client", "50095", PropertyType.PORT, "The listening port for
the monitor's http service"),
@@ -238,8 +238,9 @@ public enum Property {
   MONITOR_SSL_KEYSTOREPASS("monitor.ssl.keyStorePassword", "", PropertyType.STRING, "The
keystore password for enabling monitor SSL.", true, false),
   MONITOR_SSL_TRUSTSTORE("monitor.ssl.trustStore", "", PropertyType.PATH, "The truststore
for enabling monitor SSL.", true, false),
   MONITOR_SSL_TRUSTSTOREPASS("monitor.ssl.trustStorePassword", "", PropertyType.STRING, "The
truststore password for enabling monitor SSL.", true, false),
+  MONITOR_SSL_INCLUDE_PROTOCOLS("monitor.ssl.include.protocols", "TLSv1,TLSv1.1,TLSv1.2",
PropertyType.STRING, "A comma-separate list of allowed SSL protocols"),
   MONITOR_LOCK_CHECK_INTERVAL("monitor.lock.check.interval", "5s", PropertyType.TIMEDURATION,
"The amount of time to sleep between checking for the Montior ZooKeeper lock"),
-  
+
   TRACE_PREFIX("trace.", null, PropertyType.PREFIX, "Properties in this category affect the
behavior of distributed tracing."),
   TRACE_PORT("trace.port.client", "12234", PropertyType.PORT, "The listening port for the
trace server"),
   TRACE_TABLE("trace.table", "trace", PropertyType.STRING, "The name of the table to store
distributed traces"),
@@ -248,7 +249,7 @@ public enum Property {
   TRACE_TOKEN_PROPERTY_PREFIX("trace.token.property", null, PropertyType.PREFIX,
       "The prefix used to create a token for storing distributed traces.  For each propetry
required by trace.token.type, place this prefix in front of it."),
   TRACE_TOKEN_TYPE("trace.token.type", PasswordToken.class.getName(), PropertyType.CLASSNAME,
"An AuthenticationToken type supported by the authorizer"),
-  
+
   // per table properties
   TABLE_PREFIX("table.", null, PropertyType.PREFIX, "Properties in this category affect tablet
server treatment of tablets, but can be configured "
       + "on a per-table basis. Setting these properties in the site file will override the
default globally "
@@ -346,7 +347,7 @@ public enum Property {
   TABLE_INTERPRETER_CLASS("table.interepreter", DefaultScanInterpreter.class.getName(), PropertyType.STRING,
       "The ScanInterpreter class to apply on scan arguments in the shell"),
   TABLE_CLASSPATH("table.classpath.context", "", PropertyType.STRING, "Per table classpath
context"),
-  
+
   // VFS ClassLoader properties
   VFS_CLASSLOADER_SYSTEM_CLASSPATH_PROPERTY(AccumuloVFSClassLoader.VFS_CLASSLOADER_SYSTEM_CLASSPATH_PROPERTY,
"", PropertyType.STRING,
       "Configuration for a system level vfs classloader.  Accumulo jar can be configured
here and loaded out of HDFS."),
@@ -360,13 +361,13 @@ public enum Property {
   VFS_CLASSLOADER_CACHE_DIR(AccumuloVFSClassLoader.VFS_CACHE_DIR, "${java.io.tmpdir}" + File.separator
+ "accumulo-vfs-cache-${user.name}",
       PropertyType.ABSOLUTEPATH, "Directory to use for the vfs cache. The cache will keep
a soft reference to all of the classes loaded in the VM."
           + " This should be on local disk on each node with sufficient space. It defaults
to ${java.io.tmpdir}/accumulo-vfs-cache-${user.name}", false, true);
-  
+
   private String key, defaultValue, description;
   private PropertyType type;
   private boolean experimental;
   private boolean interpolated;
   static Logger log = Logger.getLogger(Property.class);
-  
+
   private Property(String name, String defaultValue, PropertyType type, String description,
boolean experimental, boolean interpolated) {
     this.key = name;
     this.defaultValue = defaultValue;
@@ -378,24 +379,24 @@ public enum Property {
     // also shouldn't be changing.
     this.interpolated = interpolated;
   }
-  
+
   private Property(String name, String defaultValue, PropertyType type, String description)
{
     this(name, defaultValue, type, description, false, false);
   }
-  
+
   @Override
   public String toString() {
     return this.key;
   }
-  
+
   public String getKey() {
     return this.key;
   }
-  
+
   public String getRawDefaultValue() {
     return this.defaultValue;
   }
-  
+
   public String getDefaultValue() {
     if (this.interpolated) {
       PropertiesConfiguration pconf = new PropertiesConfiguration();
@@ -413,37 +414,37 @@ public enum Property {
       return getRawDefaultValue();
     }
   }
-  
+
   public PropertyType getType() {
     return this.type;
   }
-  
+
   public String getDescription() {
     return this.description;
   }
-  
+
   public boolean isExperimental() {
     return experimental;
   }
-  
+
   private static HashSet<String> validTableProperties = null;
   private static HashSet<String> validProperties = null;
   private static HashSet<String> validPrefixes = null;
-  
+
   private static boolean isKeyValidlyPrefixed(String key) {
     for (String prefix : validPrefixes) {
       if (key.startsWith(prefix))
         return true;
     }
-    
+
     return false;
   }
-  
+
   public synchronized static boolean isValidPropertyKey(String key) {
     if (validProperties == null) {
       validProperties = new HashSet<String>();
       validPrefixes = new HashSet<String>();
-      
+
       for (Property p : Property.values()) {
         if (p.getType().equals(PropertyType.PREFIX)) {
           validPrefixes.add(p.getKey());
@@ -452,10 +453,10 @@ public enum Property {
         }
       }
     }
-    
+
     return validProperties.contains(key) || isKeyValidlyPrefixed(key);
   }
-  
+
   public synchronized static boolean isValidTablePropertyKey(String key) {
     if (validTableProperties == null) {
       validTableProperties = new HashSet<String>();
@@ -465,36 +466,36 @@ public enum Property {
         }
       }
     }
-    
+
     return validTableProperties.contains(key) || key.startsWith(Property.TABLE_CONSTRAINT_PREFIX.getKey())
         || key.startsWith(Property.TABLE_ITERATOR_PREFIX.getKey()) || key.startsWith(Property.TABLE_LOCALITY_GROUP_PREFIX.getKey());
   }
-  
+
   private static final EnumSet<Property> fixedProperties = EnumSet.of(Property.TSERV_CLIENTPORT,
Property.TSERV_NATIVEMAP_ENABLED,
       Property.TSERV_SCAN_MAX_OPENFILES, Property.MASTER_CLIENTPORT, Property.GC_PORT);
-  
+
   public static boolean isFixedZooPropertyKey(Property key) {
     return fixedProperties.contains(key);
   }
-  
+
   public static Set<Property> getFixedProperties() {
     return fixedProperties;
   }
-  
+
   public static boolean isValidZooPropertyKey(String key) {
     // white list prefixes
     return key.startsWith(Property.TABLE_PREFIX.getKey()) || key.startsWith(Property.TSERV_PREFIX.getKey())
|| key.startsWith(Property.LOGGER_PREFIX.getKey())
         || key.startsWith(Property.MASTER_PREFIX.getKey()) || key.startsWith(Property.GC_PREFIX.getKey())
         || key.startsWith(Property.MONITOR_PREFIX.getKey() + "banner.") || key.startsWith(VFS_CONTEXT_CLASSPATH_PROPERTY.getKey());
   }
-  
+
   public static Property getPropertyByKey(String key) {
     for (Property prop : Property.values())
       if (prop.getKey().equals(key))
         return prop;
     return null;
   }
-  
+
   /**
    * @return true if this is a property whose value is expected to be a java class
    */
@@ -503,7 +504,7 @@ public enum Property {
         || (key.startsWith(Property.TABLE_ITERATOR_PREFIX.getKey()) && key.substring(Property.TABLE_ITERATOR_PREFIX.getKey().length()).split("\\.").length
== 2)
         || key.equals(Property.TABLE_LOAD_BALANCER.getKey());
   }
-  
+
   public boolean isDeprecated() {
     Logger log = Logger.getLogger(getClass());
     try {
@@ -517,11 +518,11 @@ public enum Property {
     }
     return false;
   }
-  
+
   public static <T> T createInstanceFromPropertyName(AccumuloConfiguration conf, Property
property, Class<T> base, T defaultInstance) {
     String clazzName = conf.get(property);
     T instance = null;
-    
+
     try {
       Class<? extends T> clazz = AccumuloVFSClassLoader.loadClass(clazzName, base);
       instance = clazz.newInstance();
@@ -529,7 +530,7 @@ public enum Property {
     } catch (Exception e) {
       log.warn("Failed to load class ", e);
     }
-    
+
     if (instance == null) {
       log.info("Using " + defaultInstance.getClass().getName());
       instance = defaultInstance;

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7789b200/server/src/main/java/org/apache/accumulo/server/Accumulo.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/accumulo/server/Accumulo.java b/server/src/main/java/org/apache/accumulo/server/Accumulo.java
index 18c0b12..0401dab 100644
--- a/server/src/main/java/org/apache/accumulo/server/Accumulo.java
+++ b/server/src/main/java/org/apache/accumulo/server/Accumulo.java
@@ -25,6 +25,7 @@ import java.io.InputStream;
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Arrays;
 import java.util.Map.Entry;
 import java.util.TreeMap;
 
@@ -36,8 +37,8 @@ import org.apache.accumulo.core.util.AddressUtil;
 import org.apache.accumulo.core.util.UtilWaitThread;
 import org.apache.accumulo.core.util.Version;
 import org.apache.accumulo.core.zookeeper.ZooUtil;
-import org.apache.accumulo.fate.ReadOnlyTStore;
 import org.apache.accumulo.fate.ReadOnlyStore;
+import org.apache.accumulo.fate.ReadOnlyTStore;
 import org.apache.accumulo.fate.ZooStore;
 import org.apache.accumulo.server.client.HdfsZooInstance;
 import org.apache.accumulo.server.conf.ServerConfiguration;
@@ -53,9 +54,9 @@ import org.apache.log4j.helpers.LogLog;
 import org.apache.zookeeper.KeeperException;
 
 public class Accumulo {
-  
+
   private static final Logger log = Logger.getLogger(Accumulo.class);
-  
+
   public static synchronized void updateAccumuloVersion(FileSystem fs) {
     try {
       if (getAccumuloPersistentVersion(fs) == Constants.PREV_DATA_VERSION) {
@@ -67,7 +68,7 @@ public class Accumulo {
       throw new RuntimeException("Unable to set accumulo version: an error occurred.", e);
     }
   }
-  
+
   public static synchronized int getAccumuloPersistentVersion(FileSystem fs) {
     int dataVersion;
     try {
@@ -82,7 +83,7 @@ public class Accumulo {
       throw new RuntimeException("Unable to read accumulo version: an error occurred.", e);
     }
   }
-  
+
   public static void enableTracing(String address, String application) {
     try {
       DistributedTrace.enable(HdfsZooInstance.getInstance(), ZooReaderWriter.getInstance(),
application, address);
@@ -92,20 +93,20 @@ public class Accumulo {
   }
 
   public static void init(FileSystem fs, ServerConfiguration config, String application)
throws UnknownHostException {
-    
+
     System.setProperty("org.apache.accumulo.core.application", application);
-    
+
     if (System.getenv("ACCUMULO_LOG_DIR") != null)
       System.setProperty("org.apache.accumulo.core.dir.log", System.getenv("ACCUMULO_LOG_DIR"));
     else
       System.setProperty("org.apache.accumulo.core.dir.log", System.getenv("ACCUMULO_HOME")
+ "/logs/");
-    
+
     String localhost = InetAddress.getLocalHost().getHostName();
     System.setProperty("org.apache.accumulo.core.ip.localhost.hostname", localhost);
-    
+
     int logPort = config.getConfiguration().getPort(Property.MONITOR_LOG4J_PORT);
     System.setProperty("org.apache.accumulo.core.host.log.port", Integer.toString(logPort));
-    
+
     // Use a specific log config, if it exists
     String logConfig = String.format("%s/%s_logger.xml", System.getenv("ACCUMULO_CONF_DIR"),
application);
     if (!new File(logConfig).exists()) {
@@ -123,16 +124,16 @@ public class Accumulo {
     int dataVersion = Accumulo.getAccumuloPersistentVersion(fs);
     log.info("Data Version " + dataVersion);
     Accumulo.waitForZookeeperAndHdfs(fs);
-    
+
     Version codeVersion = new Version(Constants.VERSION);
     if (dataVersion != Constants.DATA_VERSION && dataVersion != Constants.PREV_DATA_VERSION)
{
       throw new RuntimeException("This version of accumulo (" + codeVersion + ") is not compatible
with files stored using data version " + dataVersion);
     }
-    
+
     TreeMap<String,String> sortedProps = new TreeMap<String,String>();
     for (Entry<String,String> entry : config.getConfiguration())
       sortedProps.put(entry.getKey(), entry.getValue());
-    
+
     for (Entry<String,String> entry : sortedProps.entrySet()) {
       if (entry.getKey().toLowerCase().contains("password") || entry.getKey().toLowerCase().contains("secret")
           || entry.getKey().startsWith(Property.TRACE_TOKEN_PROPERTY_PREFIX.getKey()))
@@ -140,12 +141,22 @@ public class Accumulo {
       else
         log.info(entry.getKey() + " = " + entry.getValue());
     }
-    
+
     monitorSwappiness();
+    
+    // Encourage users to configure TLS
+    final String SSL = "SSL";
+    for (Property sslProtocolProperty : Arrays.asList(Property.MONITOR_SSL_INCLUDE_PROTOCOLS))
{
+      String value = config.getConfiguration().get(sslProtocolProperty);
+      if (value.contains(SSL)) {
+        log.warn("It is recommended that " + sslProtocolProperty + " only allow TLS");
+      }
+    }
+
   }
-  
+
   /**
-   * 
+   *
    */
   public static void monitorSwappiness() {
     SimpleTimer.getInstance().schedule(new Runnable() {
@@ -175,7 +186,7 @@ public class Accumulo {
       }
     }, 1000, 10 * 60 * 1000);
   }
-  
+
   public static String getLocalAddress(String[] args) throws UnknownHostException {
     InetAddress result = InetAddress.getLocalHost();
     for (int i = 0; i < args.length - 1; i++) {
@@ -187,7 +198,7 @@ public class Accumulo {
     }
     return result.getHostName();
   }
-  
+
   public static void waitForZookeeperAndHdfs(FileSystem fs) {
     log.info("Attempting to talk to zookeeper");
     while (true) {
@@ -234,7 +245,7 @@ public class Accumulo {
     }
     log.info("Connected to HDFS");
   }
-  
+
   private static boolean isInSafeMode(FileSystem fs) throws IOException {
     if (!(fs instanceof DistributedFileSystem))
       return false;

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7789b200/server/src/main/java/org/apache/accumulo/server/util/EmbeddedWebServer.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/accumulo/server/util/EmbeddedWebServer.java b/server/src/main/java/org/apache/accumulo/server/util/EmbeddedWebServer.java
index 76f1826..8d62d66 100644
--- a/server/src/main/java/org/apache/accumulo/server/util/EmbeddedWebServer.java
+++ b/server/src/main/java/org/apache/accumulo/server/util/EmbeddedWebServer.java
@@ -16,10 +16,18 @@
  */
 package org.apache.accumulo.server.util;
 
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
 import javax.servlet.http.HttpServlet;
 
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.server.monitor.Monitor;
+import org.apache.commons.lang.StringUtils;
 import org.mortbay.jetty.Server;
 import org.mortbay.jetty.bio.SocketConnector;
 import org.mortbay.jetty.handler.ContextHandlerCollection;
@@ -29,22 +37,22 @@ import org.mortbay.jetty.servlet.SessionHandler;
 
 public class EmbeddedWebServer {
   private static String EMPTY = "";
-  
+
   Server server = null;
   SocketConnector sock;
   ContextHandlerCollection handler;
   Context root;
   boolean usingSsl;
-  
+
   public EmbeddedWebServer() {
     this("0.0.0.0", 0);
   }
-  
+
   public EmbeddedWebServer(String host, int port) {
     server = new Server();
     handler = new ContextHandlerCollection();
     root = new Context(handler, "/", new SessionHandler(), null, null, null);
-    
+
     if (EMPTY.equals(Monitor.getSystemConfiguration().get(Property.MONITOR_SSL_KEYSTORE))
         || EMPTY.equals(Monitor.getSystemConfiguration().get(Property.MONITOR_SSL_KEYSTOREPASS))
         || EMPTY.equals(Monitor.getSystemConfiguration().get(Property.MONITOR_SSL_TRUSTSTORE))
@@ -52,25 +60,107 @@ public class EmbeddedWebServer {
       sock = new SocketConnector();
       usingSsl = false;
     } else {
-      sock = new SslSocketConnector();
-      ((SslSocketConnector) sock).setKeystore(Monitor.getSystemConfiguration().get(Property.MONITOR_SSL_KEYSTORE));
-      ((SslSocketConnector) sock).setKeyPassword(Monitor.getSystemConfiguration().get(Property.MONITOR_SSL_KEYSTOREPASS));
-      ((SslSocketConnector) sock).setTruststore(Monitor.getSystemConfiguration().get(Property.MONITOR_SSL_TRUSTSTORE));
-      ((SslSocketConnector) sock).setTrustPassword(Monitor.getSystemConfiguration().get(Property.MONITOR_SSL_TRUSTSTOREPASS));
+      SslSocketConnector sslSock = new SslSocketConnector();
+      AccumuloConfiguration conf = Monitor.getSystemConfiguration();
+
+      // Restrict the protocols on the server socket
+      final String includeProtocols = conf.get(Property.MONITOR_SSL_INCLUDE_PROTOCOLS);
+      if (null != includeProtocols && !includeProtocols.isEmpty()) {
+        String[] protocols = StringUtils.split(includeProtocols, ',');
+        sslSock = new TLSSocketConnector(protocols);
+      }
+
+      sslSock.setKeystore(conf.get(Property.MONITOR_SSL_KEYSTORE));
+      sslSock.setKeyPassword(conf.get(Property.MONITOR_SSL_KEYSTOREPASS));
+      sslSock.setTruststore(conf.get(Property.MONITOR_SSL_TRUSTSTORE));
+      sslSock.setTrustPassword(conf.get(Property.MONITOR_SSL_TRUSTSTOREPASS));
+
       usingSsl = true;
+      sock = sslSock;
     }
     sock.setHost(host);
     sock.setPort(port);
   }
-  
+
+  /**
+   * Wrap the SocketConnector so the ServerSocket can be manipulated
+   */
+  protected static class TLSSocketConnector extends SslSocketConnector {
+
+    private final String[] protocols;
+
+    protected TLSSocketConnector(String[] protocols) {
+      this.protocols = protocols;
+    }
+
+    @Override
+    protected SSLServerSocketFactory createFactory() throws Exception {
+      return new TLSServerSocketFactory(super.createFactory(), protocols);
+    }
+  }
+
+  /**
+   * Restrict the allowed protocols to TLS on the ServerSocket
+   */
+  protected static class TLSServerSocketFactory extends SSLServerSocketFactory {
+
+    private final SSLServerSocketFactory delegate;
+    private final String[] protocols;
+
+    public TLSServerSocketFactory(SSLServerSocketFactory delegate, String[] protocols) {
+      this.delegate = delegate;
+      this.protocols = protocols;
+    }
+
+    @Override
+    public ServerSocket createServerSocket() throws IOException {
+      SSLServerSocket socket = (SSLServerSocket) delegate.createServerSocket();
+      return overrideProtocol(socket);
+    }
+
+    @Override
+    public ServerSocket createServerSocket(int port) throws IOException {
+      SSLServerSocket socket = (SSLServerSocket) delegate.createServerSocket(port);
+      return overrideProtocol(socket);
+    }
+
+    @Override
+    public ServerSocket createServerSocket(int port, int backlog) throws IOException {
+      SSLServerSocket socket = (SSLServerSocket) delegate.createServerSocket(port, backlog);
+      return overrideProtocol(socket);
+    }
+
+    @Override
+    public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress)
throws IOException {
+      SSLServerSocket socket = (SSLServerSocket) delegate.createServerSocket(port, backlog);
+      return overrideProtocol(socket);
+    }
+
+    @Override
+    public String[] getDefaultCipherSuites() {
+      return delegate.getDefaultCipherSuites();
+    }
+
+    @Override
+    public String[] getSupportedCipherSuites() {
+      return delegate.getSupportedCipherSuites();
+    }
+
+    protected ServerSocket overrideProtocol(SSLServerSocket socket) {
+      socket.setEnabledProtocols(protocols);
+      return socket;
+    }
+
+  }
+
   public void addServlet(Class<? extends HttpServlet> klass, String where) {
     root.addServlet(klass, where);
   }
-  
+
   public int getPort() {
     return sock.getLocalPort();
   }
-  
+
   public void start() {
     try {
       server.addConnector(sock);
@@ -81,7 +171,7 @@ public class EmbeddedWebServer {
       throw new RuntimeException(e);
     }
   }
-  
+
   public void stop() {
     try {
       server.stop();
@@ -89,7 +179,7 @@ public class EmbeddedWebServer {
       throw new RuntimeException(e);
     }
   }
-  
+
   public boolean isUsingSsl() {
     return usingSsl;
   }


Mime
View raw message