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

alexott pushed a commit to branch branch-0.9
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/branch-0.9 by this push:
     new 4e9f864  [ZEPPELIN-4774] TLS - create Keystores with PEM files
4e9f864 is described below

commit 4e9f864eee3ae4995b5760e03fbab6ee74ca470e
Author: Philipp Dallig <philipp.dal...@gmail.com>
AuthorDate: Wed Apr 15 11:28:49 2020 +0200

    [ZEPPELIN-4774] TLS - create Keystores with PEM files
    
    ### What is this PR for?
    This PR uses crypto functions from the [bouncycastle 
project](https://www.bouncycastle.org/). The library was already used in 
`zeppelin-interpreter`.
    
    I don't see a license link in the 
[LICENSE](https://github.com/apache/zeppelin/blob/master/LICENSE). I hope 
someone can help me to correct this situation.
    EDIT: Thanks to Leemoonsoo for clarification
    
    ### What type of PR is it?
     - Feature
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/ZEPPELIN-4774
    
    ### How should this be tested?
    * Travis-CI: https://travis-ci.org/github/Reamer/zeppelin/builds/679002184
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? Yes
    
    Author: Philipp Dallig <philipp.dal...@gmail.com>
    
    Closes #3747 from Reamer/pem_certs and squashes the following commits:
    
    6263e0bcf [Philipp Dallig] Create sslContextFactory with PEM files
    
    (cherry picked from commit 067aba81c3031275e16a689cac903ab66aefd958)
    Signed-off-by: Alex Ott <alex...@apache.org>
---
 conf/zeppelin-site.xml.template                    |  32 +++++
 docs/setup/operation/configuration.md              |  24 ++++
 pom.xml                                            |   7 +
 zeppelin-interpreter/pom.xml                       |   1 -
 .../zeppelin/conf/ZeppelinConfiguration.java       |  20 +++
 zeppelin-server/pom.xml                            |   5 +
 .../org/apache/zeppelin/server/ZeppelinServer.java |  76 ++++++++--
 .../org/apache/zeppelin/utils/PEMImporter.java     | 154 +++++++++++++++++++++
 .../org/apache/zeppelin/utils/PEMImporterTest.java | 123 ++++++++++++++++
 .../src/test/resources/example-pem-files/README.md |  22 +++
 .../privkey_with_password_PKCS_1.pem               |  54 ++++++++
 .../privkey_with_password_PKCS_8.pem               |  54 ++++++++
 .../privkey_without_password_PKCS_1.pem            |  51 +++++++
 .../privkey_without_password_PKCS_8.pem            |  52 +++++++
 .../test/resources/example-pem-files/rootCA.crt    |  29 ++++
 .../test/resources/example-pem-files/rootCA.key    |  51 +++++++
 .../resources/example-pem-files/zeppelin.com.crt   |  29 ++++
 .../resources/example-pem-files/zeppelin.com.csr   |  27 ++++
 .../resources/example-pem-files/zeppelin.com.key   |  51 +++++++
 19 files changed, 850 insertions(+), 12 deletions(-)

diff --git a/conf/zeppelin-site.xml.template b/conf/zeppelin-site.xml.template
index a1368e3..604a8eb 100755
--- a/conf/zeppelin-site.xml.template
+++ b/conf/zeppelin-site.xml.template
@@ -456,6 +456,38 @@
 </property>
 -->
 
+<!--
+<property>
+  <name>zeppelin.ssl.pem.key</name>
+  <value></value>
+  <description>This directive points to the PEM-encoded private key file for 
the server.</description>
+</property>
+-->
+
+<!--
+<property>
+  <name>zeppelin.ssl.pem.key.password</name>
+  <value></value>
+  <description>Password of the PEM-encoded private key.</description>
+</property>
+-->
+
+<!--
+<property>
+  <name>zeppelin.ssl.pem.cert</name>
+  <value></value>
+  <description>This directive points to a file with certificate data in PEM 
format.</description>
+</property>
+-->
+
+<!--
+<property>
+  <name>zeppelin.ssl.pem.ca</name>
+  <value></value>
+  <description>This directive sets the all-in-one file where you can assemble 
the Certificates of Certification Authorities (CA) whose clients you deal with. 
These are used for Client Authentication. Such a file is simply the 
concatenation of the various PEM-encoded Certificate files.</description>
+</property>
+-->
+
 <property>
   <name>zeppelin.server.allowed.origins</name>
   <value>*</value>
diff --git a/docs/setup/operation/configuration.md 
b/docs/setup/operation/configuration.md
index 584b8c2..65129ff 100644
--- a/docs/setup/operation/configuration.md
+++ b/docs/setup/operation/configuration.md
@@ -174,6 +174,30 @@ If both are defined, then the **environment variables** 
will take priority.
     <td></td>
   </tr>
   <tr>
+    <td><h6 class="properties">ZEPPELIN_SSL_PEM_KEY</h6></td>
+    <td><h6 class="properties">zeppelin.ssl.pem.key</h6></td>
+    <td></td>
+    <td>This directive points to the PEM-encoded private key file for the 
server.</td>
+  </tr>
+  <tr>
+    <td><h6 class="properties">ZEPPELIN_SSL_PEM_KEY_PASSWORD</h6></td>
+    <td><h6 class="properties">zeppelin.ssl.pem.key.password</h6></td>
+    <td></td>
+    <td>Password of the PEM-encoded private key.</td>
+  </tr>
+  <tr>
+    <td><h6 class="properties">ZEPPELIN_SSL_PEM_CERT</h6></td>
+    <td><h6 class="properties">zeppelin.ssl.pem.cert</h6></td>
+    <td></td>
+    <td>This directive points to a file with certificate data in PEM 
format.</td>
+  </tr>
+  <tr>
+    <td><h6 class="properties">ZEPPELIN_SSL_PEM_CA</h6></td>
+    <td><h6 class="properties">zeppelin.ssl.pem.ca</h6></td>
+    <td></td>
+    <td>This directive sets the all-in-one file where you can assemble the 
Certificates of Certification Authorities (CA) whose clients you deal with. 
These are used for Client Authentication. Such a file is simply the 
concatenation of the various PEM-encoded Certificate files.</td>
+  </tr>
+  <tr>
     <td><h6 class="properties">ZEPPELIN_NOTEBOOK_HOMESCREEN</h6></td>
     <td><h6 class="properties">zeppelin.notebook.homescreen</h6></td>
     <td></td>
diff --git a/pom.xml b/pom.xml
index 4b6d915..8c358f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -135,6 +135,7 @@
     <commons.cli.version>1.4</commons.cli.version>
     <shiro.version>1.4.2</shiro.version>
     <joda.version>2.9.9</joda.version>
+    <bouncycastle.version>1.60</bouncycastle.version>
 
     <hadoop2.7.version>2.7.7</hadoop2.7.version>
     <hadoop2.6.version>2.6.5</hadoop2.6.version>
@@ -330,6 +331,12 @@
         <version>${shiro.version}</version>
       </dependency>
 
+      <dependency>
+        <groupId>org.bouncycastle</groupId>
+        <artifactId>bcpkix-jdk15on</artifactId>
+        <version>${bouncycastle.version}</version>
+      </dependency>
+
       <!-- Test libraries -->
       <dependency>
         <groupId>junit</groupId>
diff --git a/zeppelin-interpreter/pom.xml b/zeppelin-interpreter/pom.xml
index 674d26c..fba105a 100644
--- a/zeppelin-interpreter/pom.xml
+++ b/zeppelin-interpreter/pom.xml
@@ -173,7 +173,6 @@
     <dependency>
       <groupId>org.bouncycastle</groupId>
       <artifactId>bcpkix-jdk15on</artifactId>
-      <version>1.60</version>
     </dependency>
 
     <dependency>
diff --git 
a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
 
b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
index 3deb8af..6e667cf 100644
--- 
a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
+++ 
b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java
@@ -395,6 +395,22 @@ public class ZeppelinConfiguration extends 
XMLConfiguration {
     }
   }
 
+  public String getPemKeyFile() {
+      return getString(ConfVars.ZEPPELIN_SSL_PEM_KEY);
+  }
+
+  public String getPemKeyPassword() {
+      return getString(ConfVars.ZEPPELIN_SSL_PEM_KEY_PASSWORD);
+  }
+
+  public String getPemCertFile() {
+      return getString(ConfVars.ZEPPELIN_SSL_PEM_CERT);
+  }
+
+  public String getPemCAFile() {
+      return getString(ConfVars.ZEPPELIN_SSL_PEM_CA);
+  }
+
   public String getNotebookDir() {
     return getRelativeDir(ConfVars.ZEPPELIN_NOTEBOOK_DIR);
   }
@@ -870,6 +886,10 @@ public class ZeppelinConfiguration extends 
XMLConfiguration {
     ZEPPELIN_SSL_KEYSTORE_TYPE("zeppelin.ssl.keystore.type", "JKS"),
     ZEPPELIN_SSL_KEYSTORE_PASSWORD("zeppelin.ssl.keystore.password", ""),
     ZEPPELIN_SSL_KEY_MANAGER_PASSWORD("zeppelin.ssl.key.manager.password", 
null),
+    ZEPPELIN_SSL_PEM_KEY("zeppelin.ssl.pem.key", null),
+    ZEPPELIN_SSL_PEM_KEY_PASSWORD("zeppelin.ssl.pem.key.password", ""),
+    ZEPPELIN_SSL_PEM_CERT("zeppelin.ssl.pem.cert", null),
+    ZEPPELIN_SSL_PEM_CA("zeppelin.ssl.pem.ca", null),
     ZEPPELIN_SSL_TRUSTSTORE_PATH("zeppelin.ssl.truststore.path", null),
     ZEPPELIN_SSL_TRUSTSTORE_TYPE("zeppelin.ssl.truststore.type", null),
     ZEPPELIN_SSL_TRUSTSTORE_PASSWORD("zeppelin.ssl.truststore.password", null),
diff --git a/zeppelin-server/pom.xml b/zeppelin-server/pom.xml
index 2d8df6d..4b25553 100644
--- a/zeppelin-server/pom.xml
+++ b/zeppelin-server/pom.xml
@@ -155,6 +155,11 @@
     </dependency>
 
     <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcpkix-jdk15on</artifactId>
+    </dependency>
+
+    <dependency>
       <groupId>commons-collections</groupId>
       <artifactId>commons-collections</artifactId>
     </dependency>
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
index e7c8d84..ec11e4b 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
@@ -20,6 +20,8 @@ import com.google.gson.Gson;
 import java.io.File;
 import java.io.IOException;
 import java.lang.management.ManagementFactory;
+import java.nio.file.Files;
+import java.security.GeneralSecurityException;
 import java.util.Base64;
 import java.util.HashSet;
 import java.util.List;
@@ -71,6 +73,7 @@ import org.apache.zeppelin.socket.NotebookServer;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.apache.zeppelin.user.Credentials;
 import org.apache.zeppelin.util.ReflectionUtils;
+import org.apache.zeppelin.utils.PEMImporter;
 import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.jmx.ConnectorServer;
 import org.eclipse.jetty.jmx.MBeanContainer;
@@ -438,24 +441,75 @@ public class ZeppelinServer extends ResourceConfig {
   private static SslContextFactory getSslContextFactory(ZeppelinConfiguration 
conf) {
     SslContextFactory.Server sslContextFactory = new 
SslContextFactory.Server();
 
-    // Set keystore
-    sslContextFactory.setKeyStorePath(conf.getKeyStorePath());
-    sslContextFactory.setKeyStoreType(conf.getKeyStoreType());
-    sslContextFactory.setKeyStorePassword(conf.getKeyStorePassword());
-    sslContextFactory.setKeyManagerPassword(conf.getKeyManagerPassword());
+    // initialize KeyStore
+    // Check for PEM files
+    if (StringUtils.isNoneBlank(conf.getPemKeyFile(), conf.getPemCertFile())) {
+      setupKeystoreWithPemFiles(sslContextFactory, conf);
+    } else {
+      // Set keystore
+      sslContextFactory.setKeyStorePath(conf.getKeyStorePath());
+      sslContextFactory.setKeyStoreType(conf.getKeyStoreType());
+      sslContextFactory.setKeyStorePassword(conf.getKeyStorePassword());
+      sslContextFactory.setKeyManagerPassword(conf.getKeyManagerPassword());
+    }
 
+    // initialize TrustStore
     if (conf.useClientAuth()) {
-      sslContextFactory.setNeedClientAuth(conf.useClientAuth());
-
-      // Set truststore
-      sslContextFactory.setTrustStorePath(conf.getTrustStorePath());
-      sslContextFactory.setTrustStoreType(conf.getTrustStoreType());
-      sslContextFactory.setTrustStorePassword(conf.getTrustStorePassword());
+      if (StringUtils.isNotBlank(conf.getPemCAFile())) {
+        setupTruststoreWithPemFiles(sslContextFactory, conf);
+      } else {
+        sslContextFactory.setNeedClientAuth(conf.useClientAuth());
+        // Set truststore
+        sslContextFactory.setTrustStorePath(conf.getTrustStorePath());
+        sslContextFactory.setTrustStoreType(conf.getTrustStoreType());
+        sslContextFactory.setTrustStorePassword(conf.getTrustStorePassword());
+      }
     }
 
     return sslContextFactory;
   }
 
+  private static void setupKeystoreWithPemFiles(SslContextFactory.Server 
sslContextFactory, ZeppelinConfiguration conf) {
+    File pemKey = new File(conf.getPemKeyFile());
+    File pemCert = new File(conf.getPemCertFile());
+    boolean isPemKeyFileReadable = Files.isReadable(pemKey.toPath());
+    boolean isPemCertFileReadable = Files.isReadable(pemCert.toPath());
+    if (!isPemKeyFileReadable) {
+      LOG.warn("PEM key file {} is not readable", pemKey);
+    }
+    if (!isPemCertFileReadable) {
+      LOG.warn("PEM cert file {} is not readable", pemCert);
+    }
+    if (isPemKeyFileReadable && isPemCertFileReadable) {
+      try {
+        String password = conf.getPemKeyPassword();
+        sslContextFactory.setKeyStore(PEMImporter.loadKeyStore(pemCert, 
pemKey, password));
+        sslContextFactory.setKeyStoreType("JKS");
+        sslContextFactory.setKeyStorePassword(password);
+      } catch (IOException | GeneralSecurityException e) {
+        LOG.error("Failed to initialize KeyStore from PEM files", e);
+      }
+    } else {
+      LOG.error("Failed to read PEM files");
+    }
+  }
+
+  private static void setupTruststoreWithPemFiles(SslContextFactory.Server 
sslContextFactory, ZeppelinConfiguration conf) {
+    File pemCa = new File(conf.getPemCAFile());
+    if (Files.isReadable(pemCa.toPath())) {
+      try {
+        sslContextFactory.setTrustStore(PEMImporter.loadTrustStore(pemCa));
+        sslContextFactory.setTrustStoreType("JKS");
+        sslContextFactory.setTrustStorePassword("");
+        sslContextFactory.setNeedClientAuth(conf.useClientAuth());
+      } catch (IOException | GeneralSecurityException e) {
+        LOG.error("Failed to initialize TrustStore from PEM CA file", e);
+      }
+    } else {
+      LOG.error("PEM CA file {} is not readable", pemCa);
+    }
+  }
+
   private static void setupRestApiContextHandler(WebAppContext webapp, 
ZeppelinConfiguration conf) {
     final ServletHolder servletHolder =
         new ServletHolder(new org.glassfish.jersey.servlet.ServletContainer());
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/PEMImporter.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/PEMImporter.java
new file mode 100644
index 0000000..467d77d
--- /dev/null
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/PEMImporter.java
@@ -0,0 +1,154 @@
+/*
+ * 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.zeppelin.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMDecryptorProvider;
+import org.bouncycastle.openssl.PEMEncryptedKeyPair;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
+import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.bouncycastle.operator.InputDecryptorProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.bouncycastle.pkcs.PKCSException;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemReader;
+
+public class PEMImporter {
+     private PEMImporter() {
+        // do nothing
+    }
+
+    public static KeyStore loadTrustStore(File certificateChainFile)
+        throws IOException, GeneralSecurityException
+    {
+        KeyStore keyStore = KeyStore.getInstance("JKS");
+        keyStore.load(null, null);
+
+        List<X509Certificate> certificateChain = 
readCertificateChain(certificateChainFile);
+        for (X509Certificate certificate : certificateChain) {
+            X500Principal principal = certificate.getSubjectX500Principal();
+            keyStore.setCertificateEntry(principal.getName("RFC2253"), 
certificate);
+        }
+        return keyStore;
+    }
+
+    public static KeyStore loadKeyStore(File certificateChainFile, File 
privateKeyFile, String keyPassword)
+        throws IOException, GeneralSecurityException
+    {
+        PrivateKey key;
+        try {
+            key = createPrivateKey(privateKeyFile, keyPassword);
+        } catch (OperatorCreationException | IOException | 
GeneralSecurityException | PKCSException e) {
+            throw new GeneralSecurityException("Private Key issues", e);
+        }
+
+        List<X509Certificate> certificateChain = 
readCertificateChain(certificateChainFile);
+        if (certificateChain.isEmpty()) {
+            throw new CertificateException("Certificate file does not contain 
any certificates: " + certificateChainFile);
+        }
+
+        KeyStore keyStore = KeyStore.getInstance("JKS");
+        keyStore.load(null, null);
+        keyStore.setKeyEntry("key", key, keyPassword.toCharArray(), 
certificateChain.stream().toArray(Certificate[]::new));
+        return keyStore;
+    }
+
+    private static List<X509Certificate> readCertificateChain(File 
certificateChainFile)
+        throws IOException, GeneralSecurityException
+    {
+        final List<X509Certificate> certs = new ArrayList<>();
+        try(final PemReader pemReader = new 
PemReader(Files.newBufferedReader(certificateChainFile.toPath())))
+        {
+            final PemObject pemObject = pemReader.readPemObject();
+            final CertificateFactory certificateFactory = 
CertificateFactory.getInstance("X509");
+            final ByteArrayInputStream bais = new 
ByteArrayInputStream(pemObject.getContent());
+
+            for (final Certificate cert : 
certificateFactory.generateCertificates(bais)) {
+                if (cert instanceof X509Certificate) {
+                    certs.add((X509Certificate) cert);
+                }
+            }
+            if (certs.isEmpty()) {
+                throw new IllegalStateException("Unable to decode certificate 
chain");
+            }
+        }
+        return certs;
+    }
+
+    private static PrivateKey createPrivateKey(File privateKeyPem, String 
keyPassword) throws IOException, GeneralSecurityException, 
OperatorCreationException, PKCSException {
+        // add provider only if it's not in the JVM
+        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+            Security.addProvider(new BouncyCastleProvider());
+        }
+        try (PEMParser parser = new 
PEMParser(Files.newBufferedReader(privateKeyPem.toPath()))) {
+            Object privateKeyObject = parser.readObject();
+            JcaPEMKeyConverter converter = new 
JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME);
+            KeyPair kp;
+            if (privateKeyObject instanceof PEMEncryptedKeyPair) {
+                // Encrypted key - we will use provided password
+                PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) 
privateKeyObject;
+                PEMDecryptorProvider decProv = new 
JcePEMDecryptorProviderBuilder().build(keyPassword.toCharArray());
+                kp = converter.getKeyPair(ckp.decryptKeyPair(decProv));
+            }
+            else if (privateKeyObject instanceof PEMKeyPair)
+            {
+                // Unencrypted key - no password needed
+                PEMKeyPair ukp = (PEMKeyPair) privateKeyObject;
+                kp = converter.getKeyPair(ukp);
+            }
+            else if (privateKeyObject instanceof PrivateKeyInfo)
+            {
+                PrivateKeyInfo pki = (PrivateKeyInfo) privateKeyObject;
+                return converter.getPrivateKey(pki);
+            }
+            else if (privateKeyObject instanceof PKCS8EncryptedPrivateKeyInfo)
+            {
+                PKCS8EncryptedPrivateKeyInfo ckp = 
(PKCS8EncryptedPrivateKeyInfo) privateKeyObject;
+                InputDecryptorProvider devProv = new 
JceOpenSSLPKCS8DecryptorProviderBuilder().build(keyPassword.toCharArray());
+                return 
converter.getPrivateKey(ckp.decryptPrivateKeyInfo(devProv));
+            }
+            else
+            {
+                throw new GeneralSecurityException("Unsupported key type: " + 
privateKeyObject.getClass());
+            }
+            return kp.getPrivate();
+        }
+    }
+}
diff --git 
a/zeppelin-server/src/test/java/org/apache/zeppelin/utils/PEMImporterTest.java 
b/zeppelin-server/src/test/java/org/apache/zeppelin/utils/PEMImporterTest.java
new file mode 100644
index 0000000..078b7ce
--- /dev/null
+++ 
b/zeppelin-server/src/test/java/org/apache/zeppelin/utils/PEMImporterTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.zeppelin.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.junit.Test;
+
+public class PEMImporterTest {
+    private final File pemkey = new 
File(this.getClass().getResource("/example-pem-files/zeppelin.com.key").getFile());
+    private final File pemCert = new 
File(this.getClass().getResource("/example-pem-files/zeppelin.com.crt").getFile());
+    private final File rootCACert = new 
File(this.getClass().getResource("/example-pem-files/rootCA.crt").getFile());
+    private final File privkeyWithPasswordPKCS1 = new 
File(this.getClass().getResource("/example-pem-files/privkey_with_password_PKCS_1.pem").getFile());
+    private final File privkeyWithPasswordPKCS8 = new 
File(this.getClass().getResource("/example-pem-files/privkey_with_password_PKCS_8.pem").getFile());
+    private final File privkeyWithoutPasswordPKCS1 = new 
File(this.getClass().getResource("/example-pem-files/privkey_without_password_PKCS_1.pem").getFile());
+    private final File privkeyWithoutPasswordPKCS8 = new 
File(this.getClass().getResource("/example-pem-files/privkey_without_password_PKCS_8.pem").getFile());
+
+    @Test
+    public void testParsingPKCS1WithoutPassword() throws IOException, 
GeneralSecurityException {
+        KeyStore keystore = PEMImporter.loadKeyStore(pemCert, 
privkeyWithoutPasswordPKCS1, "");
+        assertEquals(1, keystore.size());
+        assertTrue(keystore.containsAlias("key"));
+        assertEquals(1, keystore.getCertificateChain("key").length);
+    }
+
+    @Test
+    public void testParsingPKCS1WithPassword() throws IOException, 
GeneralSecurityException {
+        KeyStore keystore = PEMImporter.loadKeyStore(pemCert, 
privkeyWithPasswordPKCS1, "test");
+        assertEquals(1, keystore.size());
+        assertTrue(keystore.containsAlias("key"));
+        assertEquals(1, keystore.getCertificateChain("key").length);
+    }
+
+    @Test(expected = GeneralSecurityException.class)
+    public void testParsingPKCS1WithWrongPassword() throws IOException, 
GeneralSecurityException {
+        PEMImporter.loadKeyStore(pemCert, privkeyWithPasswordPKCS1, "nottest");
+    }
+
+    @Test
+    public void testParsingPKCS8WithoutPassword() throws IOException, 
GeneralSecurityException {
+        KeyStore keystore = PEMImporter.loadKeyStore(pemCert, 
privkeyWithoutPasswordPKCS8, "");
+        assertEquals(1, keystore.size());
+        assertTrue(keystore.containsAlias("key"));
+        assertEquals(1, keystore.getCertificateChain("key").length);
+    }
+
+    @Test
+    public void testParsingPKCS8WithPassword() throws IOException, 
GeneralSecurityException {
+        KeyStore keystore = PEMImporter.loadKeyStore(pemCert, 
privkeyWithPasswordPKCS8, "test");
+        assertEquals(1, keystore.size());
+        assertTrue(keystore.containsAlias("key"));
+        assertEquals(1, keystore.getCertificateChain("key").length);
+    }
+
+    @Test(expected = GeneralSecurityException.class)
+    public void testParsingPKCS8WithWrongPassword() throws IOException, 
GeneralSecurityException {
+        PEMImporter.loadKeyStore(pemCert, privkeyWithPasswordPKCS8, "nottest");
+    }
+
+    @Test
+    public void testCertKeyAndChain() throws Exception {
+        KeyStore truststore = PEMImporter.loadTrustStore(rootCACert);
+        KeyStore keystore = PEMImporter.loadKeyStore(pemCert, pemkey, "");
+        assertEquals(1, keystore.size());
+        assertTrue(keystore.containsAlias("key"));
+        assertEquals(1, keystore.getCertificateChain("key").length);
+        assertEquals(1, truststore.size());
+        Certificate[] certs = keystore.getCertificateChain("key");
+
+        PublicKey publicKey = certs[0].getPublicKey();
+        PrivateKey privateKey = (PrivateKey) keystore.getKey("key", 
"".toCharArray());
+        assertTrue(verifyPubAndPrivKey(publicKey, privateKey));
+
+        X509Certificate ca = (X509Certificate) 
truststore.getCertificate("cn=localhost");
+        X509Certificate cert = (X509Certificate) 
keystore.getCertificate("key");
+        assertTrue(verifyChain(cert, ca));
+    }
+
+    private boolean verifyPubAndPrivKey(PublicKey publicKey, PrivateKey 
privateKey) throws Exception {
+        // create a challenge
+        byte[] challenge = new byte[10000];
+        ThreadLocalRandom.current().nextBytes(challenge);
+        // sign using the private key
+        Signature sig = Signature.getInstance("SHA256withRSA");
+        sig.initSign(privateKey);
+        sig.update(challenge);
+        byte[] signature = sig.sign();
+        // verify signature using the public key
+        sig.initVerify(publicKey);
+        sig.update(challenge);
+        return sig.verify(signature);
+    }
+
+    private boolean verifyChain(X509Certificate cert, X509Certificate ca) {
+        return 
cert.getIssuerX500Principal().equals(ca.getSubjectX500Principal());
+    }
+}
diff --git a/zeppelin-server/src/test/resources/example-pem-files/README.md 
b/zeppelin-server/src/test/resources/example-pem-files/README.md
new file mode 100644
index 0000000..9bd6764
--- /dev/null
+++ b/zeppelin-server/src/test/resources/example-pem-files/README.md
@@ -0,0 +1,22 @@
+# Generate Certs and Keys
+
+## Create some private Keys
+
+Using password `test`, if needed
+
+```bash
+openssl genrsa -aes128 -passout pass:test -out 
privkey_with_password_PKCS_1.pem 4096
+openssl genrsa -aes128 -passout pass:test 4096 | openssl pkcs8 -topk8 -inform 
pem -outform pem -passin pass:test -passout pass:test -out 
privkey_with_password_PKCS_8.pem
+openssl genrsa -out privkey_without_password_PKCS_1.pem 4096
+openssl genrsa 4096 | openssl pkcs8 -topk8 -inform pem -outform pem -nocrypt 
-out privkey_without_password_PKCS_8.pem
+```
+
+## Build a small custom CA
+
+```bash
+openssl genrsa -out rootCA.key 4096
+openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out 
rootCA.crt -subj '/CN=localhost'
+openssl genrsa -out zeppelin.com.key 4096
+openssl req -new -sha256 -key zeppelin.com.key -subj "/C=US/ST=CA/O=MyOrg, 
Inc./CN=zeppelin.com" -out zeppelin.com.csr
+openssl x509 -req -in zeppelin.com.csr -CA rootCA.crt -CAkey rootCA.key 
-CAcreateserial -days 500 -sha256 -out zeppelin.com.crt
+```
\ No newline at end of file
diff --git 
a/zeppelin-server/src/test/resources/example-pem-files/privkey_with_password_PKCS_1.pem
 
b/zeppelin-server/src/test/resources/example-pem-files/privkey_with_password_PKCS_1.pem
new file mode 100644
index 0000000..3e7df10
--- /dev/null
+++ 
b/zeppelin-server/src/test/resources/example-pem-files/privkey_with_password_PKCS_1.pem
@@ -0,0 +1,54 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,B4E747CDC1182542DE863916918E8A27
+
+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
+-----END RSA PRIVATE KEY-----
diff --git 
a/zeppelin-server/src/test/resources/example-pem-files/privkey_with_password_PKCS_8.pem
 
b/zeppelin-server/src/test/resources/example-pem-files/privkey_with_password_PKCS_8.pem
new file mode 100644
index 0000000..caa3715
--- /dev/null
+++ 
b/zeppelin-server/src/test/resources/example-pem-files/privkey_with_password_PKCS_8.pem
@@ -0,0 +1,54 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+-----END ENCRYPTED PRIVATE KEY-----
diff --git 
a/zeppelin-server/src/test/resources/example-pem-files/privkey_without_password_PKCS_1.pem
 
b/zeppelin-server/src/test/resources/example-pem-files/privkey_without_password_PKCS_1.pem
new file mode 100644
index 0000000..361e534
--- /dev/null
+++ 
b/zeppelin-server/src/test/resources/example-pem-files/privkey_without_password_PKCS_1.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git 
a/zeppelin-server/src/test/resources/example-pem-files/privkey_without_password_PKCS_8.pem
 
b/zeppelin-server/src/test/resources/example-pem-files/privkey_without_password_PKCS_8.pem
new file mode 100644
index 0000000..ba85d08
--- /dev/null
+++ 
b/zeppelin-server/src/test/resources/example-pem-files/privkey_without_password_PKCS_8.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+Xqwafpkqeo8eg6d0h/o4mS15nWnXFrs=
+-----END PRIVATE KEY-----
diff --git a/zeppelin-server/src/test/resources/example-pem-files/rootCA.crt 
b/zeppelin-server/src/test/resources/example-pem-files/rootCA.crt
new file mode 100644
index 0000000..0baf11d
--- /dev/null
+++ b/zeppelin-server/src/test/resources/example-pem-files/rootCA.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFCTCCAvGgAwIBAgIUdJHlVu35JYhZrJHteNElGGqapHcwDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMDQxNTA4MTgxN1oXDTIzMDIw
+MzA4MTgxN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAyzDdVedzTxN9yDflV60HtavTPJtkaEKTwYlTT+WYVqCl
+XbuLl029JPokPH0e5nXFgvknIxgZzI3KhUw/KlJ9+vm7QERJJOEbingIwDGTcXa1
+WuiEJ5rq9yDllSNlGObdWyE59YWRXPDdVPrXAHslemsBF5HAuSN8w+mYy0wtSzkm
+u+NPy1ATWLJQe8dpW8Hrq6c3oUHivmJo3os3pwclTZCN9+/Ov6v8/1FXmhqiNnUW
+rqS36JguzPrzf4gdV0sKZlJQOUTtACUdoG/eFA1fnVDTR7O1PjMuyrmzICx55/UJ
+PNULmgu9AqJcp1McXZQrNfTpw+YJVIouSaPt3HqsEEeM+emwV4o6Y6yvRGrX5mdT
+GxbIlI31aKSz8TE/8L0a9aZz4WOOwiBUsWH4QfQcWxSDs6RoXsQZxOQSsAM5QO/t
+ZmELnhy43Uqs0y7AmCgDqwIifJdkG9/XiuA/E/hV58sU72jpcohw/sLU+/npXh5a
+HbR1KrCGJ5uPbd6FepACpRUJ1YQIna7Bwmga30CZ2LJ4NMAObt7Fzm+NLZFxUjJB
+kIK8l2deZtddGZRzsP44wkcWzDVauWv8ntgUuSQpCcAjgOvVOkN+g3dvzFvvv5/s
+EUqwxVc7AJapLtBw/TCt1jRJ0r5+kPsNtMdJxxJXl6YrLeeUYPUtcUEJ364a+YcC
+AwEAAaNTMFEwHQYDVR0OBBYEFHD/KHfgN1GHnvxKPBwgm7lfMweLMB8GA1UdIwQY
+MBaAFHD/KHfgN1GHnvxKPBwgm7lfMweLMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBAKiz60jbqNyzWgcxKDkAUt8J5ru4F9fTwW7FKVDz10baMI+v
+mvadIpCiLntXjtZmRVMD249vLTJmpOdoqxIxRYMKi8qIwwyBFmgEPQ8MqR7EZafP
+rFTsDbYiMx/QrEn45bj63jutdLMF2gb4JHYbd39SDfBaQ0ETAvvHOQhidOV9V9p7
+ymR3MRix3C6MWdZWdn3rvbiBtkqHJgYnsNePgfW4etxvWWd8OnmSOu3vlgkX2oS9
+Wu+5NHo1ZeSJDeFVY3uU/ZaKiXNqYXHTlyhe5dQ8YRPkAKQ24C+nanwzHafGLFYb
+os4dGggoMWDsdSve+4Kxx3gHCmL2tgOW627z7/DF1tfvEQVTucOdMI27eeQj3wS3
+zu1yX6M6cVshV8TZ0m9kvgGLcs+2HOR8i3pjEzl3amtQClfczGZhPG8VB/iQxR/c
+eSt57Z5Pl97rTDAuokzuRM35uhY02+1pmTJM80etew2NxLIqM0JjSuEPJBtYing6
+gZ8z3AvnNZO3U9EO8A082Wnx15Wq99VMKa2a3RHHQ5HSXiSrr7S5Jicx50LOPW2f
+znQ62XLZJztqmhKcuzQeu9QhJWA4KboGSyQmiqs8ZKEU6kGIZZsGIY8qurV0T+Ah
+bH12xIT5QbAKOb4Sle8NoyRBRcFfac1CIrDkgZ4zNufQw14eknw5lzz4bw2S
+-----END CERTIFICATE-----
diff --git a/zeppelin-server/src/test/resources/example-pem-files/rootCA.key 
b/zeppelin-server/src/test/resources/example-pem-files/rootCA.key
new file mode 100644
index 0000000..1ebaf87
--- /dev/null
+++ b/zeppelin-server/src/test/resources/example-pem-files/rootCA.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git 
a/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.crt 
b/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.crt
new file mode 100644
index 0000000..e6b253c
--- /dev/null
+++ b/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIE4jCCAsoCFERaLJLXbY8NFpydzBPhwMttq7DdMA0GCSqGSIb3DQEBCwUAMBQx
+EjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMDA0MTUwODE5NThaFw0yMTA4MjgwODE5
+NThaMEcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UECgwLTXlPcmcs
+IEluYy4xFTATBgNVBAMMDHplcHBlbGluLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJ8/+pmVNqjCcbgUbueI2f2QTRD9SUzc67WCJ2KjKS/UFs4S
+LyprC1u3aFXNH+GbrNPY3d+le3FXv6ppDXsGtjKro6wFl81T86j+ev+qSskbXxtB
+HOEZ+jEDJt1ygCG6pJdMaGj0IOCgmGLy29YRZFn4Ly7eLbBtzd7BalwYI86ZPB1v
++vpLTF8r86eaggefsJezu4O5nvQQDd8hxH5BOA1U9/2Deio+302Un0NXcQVpXUx1
+isHRB+3yMfgdptNybLeyRnTDF+zd8j5a2BArecnQdS7Ey+v/MaQD4/4G+ZZ5TKj+
+qMZs68MbFjkA+nmFnH525iCGU7gksIwuk3G3t6rBuYSNmogI/YA/9yqHv1BhwSxe
+FXPG34lLs3Mgo2E883Eq9Z5W33fpYHLk8+o59TzZxbU54gmA+7roVq0iexXdNMCO
+9ZGCvOfRLlrFjlI31qjqk9/TOlKbZAgnk3a68OCTYOB7VzgeMR1O+YQ8hM/qzWE4
+EUL/YuksprBCHJzgfSKmLr5l/hCyrZU5Mptoj70Q9J0RTM3ShUstvqQcG2APbc/Z
+xK97Jo8RvbBBj+wbfNyUpO9LyBxX1AfzSfW2tkEQp4PZUu9Pfu8H2xRbCviJQxGA
+kpfldLdWirrjNtO55BzSD2be4pubInDKx1Et2n2XEFpXdiOzI4id908DHqG1AgMB
+AAEwDQYJKoZIhvcNAQELBQADggIBALoIQJM6oMmHvtykxL4mCfdoxbQmXHIy/Ccv
+aXJuvb2gh0uZlQdHkKLd2W7Fhq+ngB3KsE4ukcFLVPVLNSmkEL1gxXSEqW9VqZNK
+gekV6Q49O+NW6OSrw0wtwNbRgKEALN3aeQfTARY1mNppWbnr5VJYPdT3SmCB6avs
+1RSLV/svFg5blHBMmCNoK1yIWyD6sZ9aL9KLHLmheBEiMQl8/aHzheFm96VV93JR
+AImEmq1V36e4QHOYUhkYqhpZOJ7ZnNiUj7XbNPfoIMeI5YvhP+dT24Aa6S9jyqsF
+gRVKQAEdmzgAv2WGyD6sSOjci9aEj/ZkrIH/qEzVxlYlkl9VnmVXWW2KBzpKcBLt
+MP6L3WmddrJ35Z3KtCJux7TJwuRdEeSo8afbLKvunVdSNxYJLzeiVx2EvgqYACkB
+gFw3wnVBGVx2ellNUe3xnp5g9+aVDui6jxYkVPzHiK+0MnrUOPELU0IPehsu6v9I
+BtgORdmIldAAihszBYGlI30AMmzh6204iWSQ5pueCzMsuBc9n7JYBeQkcCy6p+lq
+dWfBwvf8IISYCW/wT2734juPhDu+85VRyvKhYfA/gtvsM3/DDIfWUJYVKdt6NXQb
+ilOaMadPNsGkYd+ljdno5fM+KELR15Sg3GStZl6jGXjWyWaA8OtuqrXocXuSKxUN
+Nqmajx7V
+-----END CERTIFICATE-----
diff --git 
a/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.csr 
b/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.csr
new file mode 100644
index 0000000..d0a3ba3
--- /dev/null
+++ b/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.csr
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIEjDCCAnQCAQAwRzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQK
+DAtNeU9yZywgSW5jLjEVMBMGA1UEAwwMemVwcGVsaW4uY29tMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEAnz/6mZU2qMJxuBRu54jZ/ZBNEP1JTNzrtYIn
+YqMpL9QWzhIvKmsLW7doVc0f4Zus09jd36V7cVe/qmkNewa2MqujrAWXzVPzqP56
+/6pKyRtfG0Ec4Rn6MQMm3XKAIbqkl0xoaPQg4KCYYvLb1hFkWfgvLt4tsG3N3sFq
+XBgjzpk8HW/6+ktMXyvzp5qCB5+wl7O7g7me9BAN3yHEfkE4DVT3/YN6Kj7fTZSf
+Q1dxBWldTHWKwdEH7fIx+B2m03Jst7JGdMMX7N3yPlrYECt5ydB1LsTL6/8xpAPj
+/gb5lnlMqP6oxmzrwxsWOQD6eYWcfnbmIIZTuCSwjC6Tcbe3qsG5hI2aiAj9gD/3
+Koe/UGHBLF4Vc8bfiUuzcyCjYTzzcSr1nlbfd+lgcuTz6jn1PNnFtTniCYD7uuhW
+rSJ7Fd00wI71kYK859EuWsWOUjfWqOqT39M6UptkCCeTdrrw4JNg4HtXOB4xHU75
+hDyEz+rNYTgRQv9i6SymsEIcnOB9IqYuvmX+ELKtlTkym2iPvRD0nRFMzdKFSy2+
+pBwbYA9tz9nEr3smjxG9sEGP7Bt83JSk70vIHFfUB/NJ9ba2QRCng9lS709+7wfb
+FFsK+IlDEYCSl+V0t1aKuuM207nkHNIPZt7im5sicMrHUS3afZcQWld2I7MjiJ33
+TwMeobUCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4ICAQAUk6IalHU78SsapmcJqG5m
+zeiMRj2kPLLeJyuAmJQR6B0bm6UpMskwkfvsOHNj0TLcKGqBKYh6GdZj5aCH5deD
+6AYsd7IvevfehA9MJvkGjSL9IWJ8YKLr9A36XsIhZi3bmoN3Uv2aY3eEM7fHam9p
+wD1Ba/YwZLfjHLaK08ptGIMXGpM4l1SH0CoAlEv3lmz+6sxZdzKHIsXPd5qkB72I
+Da6PL88KlRjnLjfh/H+wWbGhy2ggCEB8q1iE1WG2d8RzJ5McLidP7pW4l8EPClvY
+YvcBXCxiB7iqjg8t1n/DP6+qyKPqSxl+8Oq37S+RYR8Tu+HYuujIVaQDBMFoDmIj
+rx+hYRt4G54qwn4TUpHYOthInbebJmMraHidGgQtZbw+T5tc1QxOo6jOreaMoPVW
+mV81Xbpkdhn8lgDqT9hBXSSzo+WTc2eHrZgAsm5Cms+2/Yjh56YJzUMXLDXmApeS
+a2ruoYHrwUueNiqhtyL+mC9yFX8GfHMcVu4ujQHr/zSkxjdAe7xUOcNCkpE7qz2w
+2mBksnYag2ho1qbqFz1NXLVK+ZF4n46CggxsPdjflZ7xTdgRCzxIHvH/FDTMB94H
+zHC1lDjQxc67gzKeoRIM4iNLva/kcXUdXCRcK7aQSA5J2FdCeWJOCMlkzlMFaCQv
+J0huh/0U66B+8DCTAVJuMw==
+-----END CERTIFICATE REQUEST-----
diff --git 
a/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.key 
b/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.key
new file mode 100644
index 0000000..063353f
--- /dev/null
+++ b/zeppelin-server/src/test/resources/example-pem-files/zeppelin.com.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----

Reply via email to