You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by vo...@apache.org on 2020/03/10 18:41:35 UTC

[drill] 06/10: DRILL-7625: Add options for SslContextFactory

This is an automated email from the ASF dual-hosted git repository.

volodymyr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git

commit f44f335473b587ceab9aa5043ac5bfbe172c7426
Author: Igor Guzenko <ih...@gmail.com>
AuthorDate: Mon Mar 2 17:09:54 2020 +0200

    DRILL-7625: Add options for SslContextFactory
    
    closes #2012
---
 .../src/main/resources/drill-override-example.conf |  66 +++++++
 .../java/org/apache/drill/exec/ExecConstants.java  |  32 +++
 .../apache/drill/exec/server/rest/WebServer.java   | 121 ++----------
 .../rest/ssl/SslContextFactoryConfigurator.java    | 214 +++++++++++++++++++++
 .../org/apache/drill/exec/ssl/SSLConfigServer.java |  16 +-
 .../ssl/SslContextFactoryConfiguratorTest.java     |  71 +++++++
 6 files changed, 404 insertions(+), 116 deletions(-)

diff --git a/distribution/src/main/resources/drill-override-example.conf b/distribution/src/main/resources/drill-override-example.conf
index ad942bb..2dec959 100644
--- a/distribution/src/main/resources/drill-override-example.conf
+++ b/distribution/src/main/resources/drill-override-example.conf
@@ -113,6 +113,72 @@ drill.exec: {
         # Location to keytab file for above spnego principal
         spnego.keytab: "<keytab_file_location>";
     },
+    jetty: {
+      server: {
+        # Optional params to set on Jetty's org.eclipse.jetty.util.ssl.SslContextFactory when drill.exec.http.ssl_enabled
+        sslContextFactory: {
+          # allows to specify cert to use when multiple non-SNI certificates are available.
+          certAlias: "certAlias",
+          # path to file that contains Certificate Revocation List
+          crlPath: "/etc/file.crl",
+          # enable Certificate Revocation List Distribution Points Support
+          enableCRLDP: false,
+          # enable On-Line Certificate Status Protocol support
+          enableOCSP: false,
+          # when set to "HTTPS" hostname verification will be enabled
+          endpointIdentificationAlgorithm: "HTTPS",
+          # accepts exact cipher suite names and/or regular expressions.
+          excludeCipherSuites: ["SSL_DHE_DSS_WITH_DES_CBC_SHA"],
+          # list of TLS/SSL protocols to exclude
+          excludeProtocols: ["TLSv1.1"],
+          # accepts exact cipher suite names and/or regular expressions.
+          includeCipherSuites: ["SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"],
+          # list of TLS/SSL protocols to include
+          includeProtocols: ["TLSv1.2", "TLSv1.3"],
+          # the algorithm name (default "SunX509") used by the javax.net.ssl.KeyManagerFactory
+          keyManagerFactoryAlgorithm: "SunX509",
+          # classname of custom java.security.Provider implementation
+          keyStoreProvider: null,
+          # type of key store (default "JKS")
+          keyStoreType: "JKS",
+          # max number of intermediate certificates in sertificate chain
+          maxCertPathLength: -1,
+          # set true if ssl needs client authentication
+          needClientAuth: false,
+          # location of the OCSP Responder
+          ocspResponderURL: "",
+          # javax.net.ssl.SSLContext provider
+          provider: null,
+          # whether TLS renegotiation is allowed
+          renegotiationAllowed: false,
+          # number of renegotions allowed for this connection (-1 for unlimited, default 5) .
+          renegotiationLimit: 5,
+          # algorithm name for java.security.SecurityRandom instances.
+          # https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecureRandom
+          secureRandomAlgorithm: "NativePRNG",
+          # set the flag to enable SSL Session caching
+          sessionCachingEnabled: false,
+          # set if you want to bound session cache size
+          sslSessionCacheSize: -1,
+          # session timeout in seconds.
+          sslSessionTimeout: -1,
+          # the algorithm name (default "SunX509") used by the javax.net.ssl.TrustManagerFactory
+          trustManagerFactoryAlgorithm: "SunX509",
+          # provider of the trust store
+          trustStoreProvider: null,
+          # type of the trust store (default "JKS")
+          trustStoreType: "JKS",
+          # sets whether the local cipher suites preference should be honored.
+          useCipherSuiteOrder: false,
+          # true if SSL certificates have to be validated
+          validateCerts: false,
+          # true if SSL certificates of the peer have to be validated
+          validatePeerCerts: false,
+          # true if SSL wants client authentication.
+          wantClientAuth: false
+        }
+      }
+    }
   },
   # Below SSL parameters need to be set for custom transport layer settings.
   ssl: {
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java b/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java
index d0a4718..2e3a9cf 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/ExecConstants.java
@@ -212,6 +212,38 @@ public final class ExecConstants {
   public static final String HTTP_JETTY_SERVER_ACCEPTORS = "drill.exec.http.jetty.server.acceptors";
   public static final String HTTP_JETTY_SERVER_SELECTORS = "drill.exec.http.jetty.server.selectors";
   public static final String HTTP_JETTY_SERVER_HANDLERS = "drill.exec.http.jetty.server.handlers";
+
+  public static final String HTTP_JETTY_SSL_CONTEXT_FACTORY_OPTIONS_PREFIX = "drill.exec.http.jetty.server.sslContextFactory";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_CERT_ALIAS = "drill.exec.http.jetty.server.sslContextFactory.certAlias";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_CRL_PATH = "drill.exec.http.jetty.server.sslContextFactory.crlPath";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_ENABLE_CRLDP = "drill.exec.http.jetty.server.sslContextFactory.enableCRLDP";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_ENABLE_OCSP = "drill.exec.http.jetty.server.sslContextFactory.enableOCSP";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_ENDPOINT_IDENTIFICATION_ALGORITHM = "drill.exec.http.jetty.server.sslContextFactory.endpointIdentificationAlgorithm";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_EXCLUDE_CIPHER_SUITES = "drill.exec.http.jetty.server.sslContextFactory.excludeCipherSuites";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_EXCLUDE_PROTOCOLS = "drill.exec.http.jetty.server.sslContextFactory.excludeProtocols";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_INCLUDE_CIPHER_SUITES = "drill.exec.http.jetty.server.sslContextFactory.includeCipherSuites";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_INCLUDE_PROTOCOLS = "drill.exec.http.jetty.server.sslContextFactory.includeProtocols";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_KEY_MANAGER_FACTORY_ALGORITHM = "drill.exec.http.jetty.server.sslContextFactory.keyManagerFactoryAlgorithm";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_KEYSTORE_PROVIDER = "drill.exec.http.jetty.server.sslContextFactory.keyStoreProvider";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_KEYSTORE_TYPE = "drill.exec.http.jetty.server.sslContextFactory.keyStoreType";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_MAX_CERT_PATH_LENGTH = "drill.exec.http.jetty.server.sslContextFactory.maxCertPathLength";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_NEED_CLIENT_AUTH = "drill.exec.http.jetty.server.sslContextFactory.needClientAuth";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_OCSP_RESPONDER_URL = "drill.exec.http.jetty.server.sslContextFactory.ocspResponderURL";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_PROVIDER = "drill.exec.http.jetty.server.sslContextFactory.provider";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_RENEGOTIATION_ALLOWED = "drill.exec.http.jetty.server.sslContextFactory.renegotiationAllowed";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_RENEGOTIATION_LIMIT = "drill.exec.http.jetty.server.sslContextFactory.renegotiationLimit";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SECURE_RANDOM_ALGORITHM = "drill.exec.http.jetty.server.sslContextFactory.secureRandomAlgorithm";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SESSION_CACHING_ENABLED = "drill.exec.http.jetty.server.sslContextFactory.sessionCachingEnabled";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SSL_SESSION_CACHE_SIZE = "drill.exec.http.jetty.server.sslContextFactory.sslSessionCacheSize";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SSL_SESSION_TIMEOUT = "drill.exec.http.jetty.server.sslContextFactory.sslSessionTimeout";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_TRUSTMANAGERFACTORY_ALGORITHM = "drill.exec.http.jetty.server.sslContextFactory.trustManagerFactoryAlgorithm";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_TRUSTSTORE_PROVIDER = "drill.exec.http.jetty.server.sslContextFactory.trustStoreProvider";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_TRUSTSTORE_TYPE = "drill.exec.http.jetty.server.sslContextFactory.trustStoreType";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_USE_CIPHER_SUITE_ORDER = "drill.exec.http.jetty.server.sslContextFactory.useCipherSuiteOrder";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_VALIDATE_CERTS = "drill.exec.http.jetty.server.sslContextFactory.validateCerts";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_VALIDATE_PEER_CERTS = "drill.exec.http.jetty.server.sslContextFactory.validatePeerCerts";
+  public static final String HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_WANT_CLIENT_AUTH = "drill.exec.http.jetty.server.sslContextFactory.wantClientAuth";
+
   public static final String HTTP_ENABLE_SSL = "drill.exec.http.ssl_enabled";
   public static final String HTTP_CLIENT_TIMEOUT = "drill.exec.http.client.timeout";
   public static final String HTTP_CORS_ENABLED = "drill.exec.http.cors.enabled";
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/WebServer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/WebServer.java
index b648de5..0e937d0 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/WebServer.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/WebServer.java
@@ -22,13 +22,12 @@ import com.codahale.metrics.servlets.MetricsServlet;
 import com.codahale.metrics.servlets.ThreadDumpServlet;
 
 import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringEscapeUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.drill.common.config.DrillConfig;
 import org.apache.drill.common.exceptions.DrillException;
 import org.apache.drill.exec.ExecConstants;
-import org.apache.drill.exec.ssl.SSLConfig;
+import org.apache.drill.exec.server.rest.ssl.SslContextFactoryConfigurator;
 import org.apache.drill.exec.exception.DrillbitStartupException;
 import org.apache.drill.exec.expr.fn.registry.FunctionHolder;
 import org.apache.drill.exec.expr.fn.registry.LocalFunctionRegistry;
@@ -40,15 +39,7 @@ import org.apache.drill.exec.server.options.OptionValidator.OptionDescription;
 import org.apache.drill.exec.server.options.OptionValue;
 import org.apache.drill.exec.server.rest.auth.DrillErrorHandler;
 import org.apache.drill.exec.server.rest.auth.DrillHttpSecurityHandlerProvider;
-import org.apache.drill.exec.ssl.SSLConfigBuilder;
 import org.apache.drill.exec.work.WorkManager;
-import org.bouncycastle.asn1.x500.X500NameBuilder;
-import org.bouncycastle.asn1.x500.style.BCStyle;
-import org.bouncycastle.cert.X509v3CertificateBuilder;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
 import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.security.SecurityHandler;
 import org.eclipse.jetty.security.authentication.SessionAuthentication;
@@ -71,7 +62,6 @@ import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
 import org.glassfish.jersey.servlet.ServletContainer;
-import org.joda.time.DateTime;
 
 import javax.servlet.DispatcherType;
 import javax.servlet.http.HttpSession;
@@ -82,18 +72,11 @@ import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
-import java.math.BigInteger;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.SecureRandom;
-import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.TreeSet;
@@ -161,26 +144,24 @@ public class WebServer implements AutoCloseable {
       return;
     }
 
-    final boolean authEnabled = config.getBoolean(ExecConstants.USER_AUTHENTICATION_ENABLED);
 
-    int port = config.getInt(ExecConstants.HTTP_PORT);
-    final boolean portHunt = config.getBoolean(ExecConstants.HTTP_PORT_HUNT);
-    final int acceptors = config.getInt(ExecConstants.HTTP_JETTY_SERVER_ACCEPTORS);
-    final int selectors = config.getInt(ExecConstants.HTTP_JETTY_SERVER_SELECTORS);
-    final int handlers = config.getInt(ExecConstants.HTTP_JETTY_SERVER_HANDLERS);
     final QueuedThreadPool threadPool = new QueuedThreadPool(2, 2);
     embeddedJetty = new Server(threadPool);
+
+    final boolean authEnabled = config.getBoolean(ExecConstants.USER_AUTHENTICATION_ENABLED);
     ServletContextHandler webServerContext = createServletContextHandler(authEnabled);
-    //Allow for Other Drillbits to make REST calls
-    FilterHolder filterHolder = new FilterHolder(CrossOriginFilter.class);
-    filterHolder.setInitParameter("allowedOrigins", "*");
-    //Allowing CORS for metrics only
-    webServerContext.addFilter(filterHolder, STATUS_METRICS_PATH, null);
     embeddedJetty.setHandler(webServerContext);
 
+    final int acceptors = config.getInt(ExecConstants.HTTP_JETTY_SERVER_ACCEPTORS);
+    final int selectors = config.getInt(ExecConstants.HTTP_JETTY_SERVER_SELECTORS);
+    int port = config.getInt(ExecConstants.HTTP_PORT);
     ServerConnector connector = createConnector(port, acceptors, selectors);
+
+    final int handlers = config.getInt(ExecConstants.HTTP_JETTY_SERVER_HANDLERS);
     threadPool.setMaxThreads(handlers + connector.getAcceptors() + connector.getSelectorManager().getSelectorCount());
     embeddedJetty.addConnector(connector);
+
+    final boolean portHunt = config.getBoolean(ExecConstants.HTTP_PORT_HUNT);
     for (int retry = 0; retry < PORT_HUNT_TRIES; retry++) {
       connector.setPort(port);
       try {
@@ -264,6 +245,12 @@ public class WebServer implements AutoCloseable {
       }
     }
 
+    //Allow for Other Drillbits to make REST calls
+    FilterHolder filterHolder = new FilterHolder(CrossOriginFilter.class);
+    filterHolder.setInitParameter("allowedOrigins", "*");
+    //Allowing CORS for metrics only
+    servletContextHandler.addFilter(filterHolder, STATUS_METRICS_PATH, null);
+
     return servletContextHandler;
   }
 
@@ -346,79 +333,9 @@ public class WebServer implements AutoCloseable {
    */
   private ServerConnector createHttpsConnector(int port, int acceptors, int selectors) throws Exception {
     logger.info("Setting up HTTPS connector for web server");
-
-    final SslContextFactory sslContextFactory = new SslContextFactory();
-    SSLConfig ssl = new SSLConfigBuilder()
-        .config(config)
-        .mode(SSLConfig.Mode.SERVER)
-        .initializeSSLContext(false)
-        .validateKeyStore(true)
-        .build();
-    if (ssl.isSslValid()) {
-      logger.info("Using configured SSL settings for web server");
-
-      sslContextFactory.setKeyStorePath(ssl.getKeyStorePath());
-      sslContextFactory.setKeyStorePassword(ssl.getKeyStorePassword());
-      sslContextFactory.setKeyManagerPassword(ssl.getKeyPassword());
-      if(ssl.hasTrustStorePath()){
-        sslContextFactory.setTrustStorePath(ssl.getTrustStorePath());
-        if(ssl.hasTrustStorePassword()){
-          sslContextFactory.setTrustStorePassword(ssl.getTrustStorePassword());
-        }
-      }
-    } else {
-      logger.info("Using generated self-signed SSL settings for web server");
-      final SecureRandom random = new SecureRandom();
-
-      // Generate a private-public key pair
-      final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
-      keyPairGenerator.initialize(1024, random);
-      final KeyPair keyPair = keyPairGenerator.generateKeyPair();
-
-      final DateTime now = DateTime.now();
-
-      // Create builder for certificate attributes
-      final X500NameBuilder nameBuilder = new X500NameBuilder(BCStyle.INSTANCE)
-          .addRDN(BCStyle.OU, "Apache Drill (auth-generated)")
-          .addRDN(BCStyle.O, "Apache Software Foundation (auto-generated)")
-          .addRDN(BCStyle.CN, workManager.getContext().getEndpoint().getAddress());
-
-      final Date notBefore = now.minusMinutes(1).toDate();
-      final Date notAfter = now.plusYears(5).toDate();
-      final BigInteger serialNumber = new BigInteger(128, random);
-
-      // Create a certificate valid for 5years from now.
-      final X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(
-          nameBuilder.build(), // attributes
-          serialNumber,
-          notBefore,
-          notAfter,
-          nameBuilder.build(),
-          keyPair.getPublic());
-
-      // Sign the certificate using the private key
-      final ContentSigner contentSigner =
-          new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate());
-      final X509Certificate certificate =
-          new JcaX509CertificateConverter().getCertificate(certificateBuilder.build(contentSigner));
-
-      // Check the validity
-      certificate.checkValidity(now.toDate());
-
-      // Make sure the certificate is self-signed.
-      certificate.verify(certificate.getPublicKey());
-
-      // Generate a random password for keystore protection
-      final String keyStorePasswd = RandomStringUtils.random(20);
-      final KeyStore keyStore = KeyStore.getInstance("JKS");
-      keyStore.load(null, null);
-      keyStore.setKeyEntry("DrillAutoGeneratedCert", keyPair.getPrivate(),
-          keyStorePasswd.toCharArray(), new java.security.cert.Certificate[]{certificate});
-
-      sslContextFactory.setKeyStore(keyStore);
-      sslContextFactory.setKeyStorePassword(keyStorePasswd);
-    }
-
+    SslContextFactory sslContextFactory = new SslContextFactoryConfigurator(config,
+        workManager.getContext().getEndpoint().getAddress())
+        .configureNewSslContextFactory();
     final HttpConfiguration httpsConfig = baseHttpConfig();
     httpsConfig.addCustomizer(new SecureRequestCustomizer());
 
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfigurator.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfigurator.java
new file mode 100644
index 0000000..a5aa541
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfigurator.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.server.rest.ssl;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.exec.ExecConstants;
+import org.apache.drill.exec.ssl.SSLConfig;
+import org.apache.drill.exec.ssl.SSLConfigBuilder;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Configures {@link SslContextFactory} when https is enabled for Web UI
+ */
+public class SslContextFactoryConfigurator {
+  private static final Logger logger = LoggerFactory.getLogger(SslContextFactoryConfigurator.class);
+
+  private final DrillConfig config;
+  private final String drillbitEndpointAddress;
+
+  public SslContextFactoryConfigurator(DrillConfig config, String drillbitEndpointAddress) {
+    this.config = config;
+    this.drillbitEndpointAddress = drillbitEndpointAddress;
+  }
+
+  /**
+   * Tries to apply ssl options configured by user. If provided configuration isn't valid,
+   * new self-signed certificate will be generated and used in sslContextFactory.
+   *
+   * @return new configured sslContextFactory
+   * @throws Exception when generation of self-signed certificate failed
+   */
+  public SslContextFactory configureNewSslContextFactory() throws Exception {
+    SSLConfig sslConf = new SSLConfigBuilder()
+        .config(config)
+        .mode(SSLConfig.Mode.SERVER)
+        .initializeSSLContext(false)
+        .validateKeyStore(true)
+        .build();
+    final SslContextFactory sslContextFactory = new SslContextFactory();
+    if (sslConf.isSslValid()) {
+      useOptionsConfiguredByUser(sslContextFactory, sslConf);
+    } else {
+      useAutoGeneratedSelfSignedCertificate(sslContextFactory);
+    }
+    return sslContextFactory;
+  }
+
+  private void useOptionsConfiguredByUser(SslContextFactory sslFactory, SSLConfig sslConf) {
+    logger.info("Using configured SSL settings for web server");
+    sslFactory.setKeyStorePath(sslConf.getKeyStorePath());
+    sslFactory.setKeyStorePassword(sslConf.getKeyStorePassword());
+    sslFactory.setKeyManagerPassword(sslConf.getKeyPassword());
+    if (sslConf.hasTrustStorePath()) {
+      sslFactory.setTrustStorePath(sslConf.getTrustStorePath());
+      if (sslConf.hasTrustStorePassword()) {
+        sslFactory.setTrustStorePassword(sslConf.getTrustStorePassword());
+      }
+    }
+    sslFactory.setProtocol(sslConf.getProtocol());
+    sslFactory.setIncludeProtocols(sslConf.getProtocol());
+    if (config.hasPath(ExecConstants.HTTP_JETTY_SSL_CONTEXT_FACTORY_OPTIONS_PREFIX)) {
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_CERT_ALIAS, sslFactory::setCertAlias);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_CRL_PATH, sslFactory::setCrlPath);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_ENABLE_CRLDP, sslFactory::setEnableCRLDP);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_ENABLE_OCSP, sslFactory::setEnableOCSP);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_ENDPOINT_IDENTIFICATION_ALGORITHM, sslFactory::setEndpointIdentificationAlgorithm);
+      setStringArrayIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_EXCLUDE_CIPHER_SUITES, sslFactory::setExcludeCipherSuites);
+      setStringArrayIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_EXCLUDE_PROTOCOLS, sslFactory::setExcludeProtocols);
+      setStringArrayIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_INCLUDE_CIPHER_SUITES, sslFactory::setIncludeCipherSuites);
+      setStringArrayIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_INCLUDE_PROTOCOLS, sslFactory::setIncludeProtocols);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_KEY_MANAGER_FACTORY_ALGORITHM, sslFactory::setKeyManagerFactoryAlgorithm);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_KEYSTORE_PROVIDER, sslFactory::setKeyStoreProvider);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_KEYSTORE_TYPE, sslFactory::setKeyStoreType);
+      setIntIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_MAX_CERT_PATH_LENGTH, sslFactory::setMaxCertPathLength);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_NEED_CLIENT_AUTH, sslFactory::setNeedClientAuth);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_OCSP_RESPONDER_URL, sslFactory::setOcspResponderURL);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_PROVIDER, sslFactory::setProvider);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_RENEGOTIATION_ALLOWED, sslFactory::setRenegotiationAllowed);
+      setIntIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_RENEGOTIATION_LIMIT, sslFactory::setRenegotiationLimit);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SECURE_RANDOM_ALGORITHM, sslFactory::setSecureRandomAlgorithm);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SESSION_CACHING_ENABLED, sslFactory::setSessionCachingEnabled);
+      setIntIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SSL_SESSION_CACHE_SIZE, sslFactory::setSslSessionCacheSize);
+      setIntIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SSL_SESSION_TIMEOUT, sslFactory::setSslSessionTimeout);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_TRUSTMANAGERFACTORY_ALGORITHM, sslFactory::setTrustManagerFactoryAlgorithm);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_TRUSTSTORE_PROVIDER, sslFactory::setTrustStoreProvider);
+      setStringIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_TRUSTSTORE_TYPE, sslFactory::setTrustStoreType);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_USE_CIPHER_SUITE_ORDER, sslFactory::setUseCipherSuitesOrder);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_VALIDATE_CERTS, sslFactory::setValidateCerts);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_VALIDATE_PEER_CERTS, sslFactory::setValidatePeerCerts);
+      setBooleanIfPresent(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_WANT_CLIENT_AUTH, sslFactory::setWantClientAuth);
+    }
+  }
+
+  private void setStringArrayIfPresent(String optKey, Consumer<String[]> optSet) {
+    setIfPresent(optKey,
+        key -> {
+          List<String> list = config.getStringList(key);
+          return list == null ? null : list.toArray(new String[0]);
+        },
+        optSet);
+  }
+
+  private void setBooleanIfPresent(String optKey, Consumer<Boolean> optSet) {
+    setIfPresent(optKey, config::getBoolean, optSet);
+  }
+
+  private void setStringIfPresent(String optKey, Consumer<String> optSet) {
+    setIfPresent(optKey, config::getString, optSet);
+  }
+
+  private void setIntIfPresent(String optKey, Consumer<Integer> optSet) {
+    setIfPresent(optKey, config::getInt, optSet);
+  }
+
+  private <T> void setIfPresent(String optKey, Function<String, T> optGet, Consumer<T> optSet) {
+    if (config.hasPath(optKey)) {
+      T optVal = optGet.apply(optKey);
+      if (optVal != null) {
+        optSet.accept(optVal);
+      }
+    }
+  }
+
+
+  private void useAutoGeneratedSelfSignedCertificate(SslContextFactory sslContextFactory) throws Exception {
+    logger.info("Using generated self-signed SSL settings for web server");
+    final SecureRandom random = new SecureRandom();
+
+    // Generate a private-public key pair
+    final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+    keyPairGenerator.initialize(1024, random);
+    final KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+
+    // Create builder for certificate attributes
+    final X500NameBuilder nameBuilder = new X500NameBuilder(BCStyle.INSTANCE)
+        .addRDN(BCStyle.OU, "Apache Drill (auth-generated)")
+        .addRDN(BCStyle.O, "Apache Software Foundation (auto-generated)")
+        .addRDN(BCStyle.CN, drillbitEndpointAddress);
+
+    final DateTime now = DateTime.now();
+    final Date notBefore = now.minusMinutes(1).toDate();
+    final Date notAfter = now.plusYears(5).toDate();
+    final BigInteger serialNumber = new BigInteger(128, random);
+
+    // Create a certificate valid for 5years from now.
+    final X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(
+        nameBuilder.build(), // attributes
+        serialNumber,
+        notBefore,
+        notAfter,
+        nameBuilder.build(),
+        keyPair.getPublic());
+
+    // Sign the certificate using the private key
+    final ContentSigner contentSigner =
+        new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate());
+    final X509Certificate certificate =
+        new JcaX509CertificateConverter().getCertificate(certificateBuilder.build(contentSigner));
+
+    // Check the validity
+    certificate.checkValidity(now.toDate());
+
+    // Make sure the certificate is self-signed.
+    certificate.verify(certificate.getPublicKey());
+
+    // Generate a random password for keystore protection
+    final String keyStorePasswd = RandomStringUtils.random(20);
+    final KeyStore keyStore = KeyStore.getInstance("JKS");
+    keyStore.load(null, null);
+    keyStore.setKeyEntry("DrillAutoGeneratedCert", keyPair.getPrivate(),
+        keyStorePasswd.toCharArray(), new java.security.cert.Certificate[]{certificate});
+
+    sslContextFactory.setKeyStore(keyStore);
+    sslContextFactory.setKeyStorePassword(keyStorePasswd);
+  }
+}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/ssl/SSLConfigServer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/ssl/SSLConfigServer.java
index e0b8f54..53d2616 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/ssl/SSLConfigServer.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/ssl/SSLConfigServer.java
@@ -90,7 +90,7 @@ public class SSLConfigServer extends SSLConfig {
     String keyPass = getConfigParam(ExecConstants.SSL_KEY_PASSWORD,
         resolveHadoopPropertyName(HADOOP_SSL_KEYSTORE_KEYPASSWORD_TPL_KEY, mode));
     keyPassword = keyPass.isEmpty() ? keyStorePassword : keyPass;
-    protocol = getConfigParamWithDefault(ExecConstants.SSL_PROTOCOL, DEFAULT_SSL_PROTOCOL);
+    protocol = config.getString(ExecConstants.SSL_PROTOCOL);
     // If provider is OPENSSL then to debug or run this code in an IDE, you will need to enable
     // the dependency on netty-tcnative with the correct classifier for the platform you use.
     // This can be done by enabling the openssl profile.
@@ -99,7 +99,7 @@ public class SSLConfigServer extends SSLConfig {
     // or from your local maven repository:
     // ~/.m2/repository/kr/motd/maven/os-maven-plugin/1.6.1/os-maven-plugin-1.6.1.jar
     // Note that installing this plugin may require you to start with a new workspace
-    provider = getConfigParamWithDefault(ExecConstants.SSL_PROVIDER, DEFAULT_SSL_PROVIDER);
+    provider = config.getString(ExecConstants.SSL_PROVIDER);
   }
 
   public void validateKeyStore() throws DrillException {
@@ -222,18 +222,6 @@ public class SSLConfigServer extends SSLConfig {
     return value;
   }
 
-  private String getConfigParamWithDefault(String name, String defaultValue) {
-    String value = "";
-    if (config.hasPath(name)) {
-      value = config.getString(name);
-    }
-    if (value.isEmpty()) {
-      value = defaultValue;
-    }
-    value = value.trim();
-    return value;
-  }
-
   private String resolveHadoopPropertyName(String nameTemplate, Mode mode) {
     return MessageFormat.format(nameTemplate, mode.toString().toLowerCase());
   }
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfiguratorTest.java b/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfiguratorTest.java
new file mode 100644
index 0000000..6a184fb
--- /dev/null
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfiguratorTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.server.rest.ssl;
+
+import java.util.Arrays;
+
+import org.apache.drill.categories.OptionsTest;
+import org.apache.drill.exec.ExecConstants;
+import org.apache.drill.test.ClusterFixture;
+import org.apache.drill.test.ClusterFixtureBuilder;
+import org.apache.drill.test.ClusterTest;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+@Category(OptionsTest.class)
+public class SslContextFactoryConfiguratorTest extends ClusterTest {
+
+  private static SslContextFactoryConfigurator sslContextFactoryConfigurator;
+
+  @BeforeClass
+  public static void setUpClass() throws Exception {
+    ClusterFixtureBuilder fixtureBuilder = ClusterFixture.builder(dirTestWatcher)
+        // imitate proper ssl config for embedded web
+        .configProperty(ExecConstants.SSL_PROTOCOL, "TLSv1.2")
+        .configProperty(ExecConstants.HTTP_ENABLE_SSL, true)
+        .configProperty(ExecConstants.HTTP_TRUSTSTORE_PATH, "/tmp/ssl/cacerts.jks")
+        .configProperty(ExecConstants.HTTP_TRUSTSTORE_PASSWORD, "passphrase")
+        .configProperty(ExecConstants.HTTP_KEYSTORE_PATH, "/tmp/ssl/keystore.jks")
+        .configProperty(ExecConstants.HTTP_KEYSTORE_PASSWORD, "passphrase")
+        .configProperty(ExecConstants.SSL_KEY_PASSWORD, "passphrase")
+        .configProperty(ExecConstants.SSL_USE_HADOOP_CONF, false)
+
+        // few specific opts for Jetty sslContextFactory
+        .configProperty(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_SSL_SESSION_TIMEOUT, 30)
+        .configProperty(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_WANT_CLIENT_AUTH, true);
+    fixtureBuilder.configBuilder().put(ExecConstants.HTTP_JETTY_SERVER_SSL_CONTEXT_FACTORY_EXCLUDE_PROTOCOLS,
+        Arrays.asList("TLSv1.0", "TLSv1.1"));
+    startCluster(fixtureBuilder);
+    sslContextFactoryConfigurator = new SslContextFactoryConfigurator(cluster.config(), cluster.drillbit().getContext().getEndpoint().getAddress());
+  }
+
+  @Test
+  public void configureNewSslContextFactory() throws Exception {
+    SslContextFactory sslContextFactory = sslContextFactoryConfigurator.configureNewSslContextFactory();
+
+    assertEquals(30, sslContextFactory.getSslSessionTimeout());
+    assertTrue(sslContextFactory.getWantClientAuth());
+    assertArrayEquals(new String[]{"TLSv1.0", "TLSv1.1"}, sslContextFactory.getExcludeProtocols());
+  }
+}