Bladeren bron

HADOOP-10658. SSLFactory expects truststores being configured. Contributed by Alejandro Abdelnur.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1599435 13f79535-47bb-0310-9956-ffa450edef68
Aaron Myers 11 jaren geleden
bovenliggende
commit
0634b42366

+ 2 - 0
hadoop-common-project/hadoop-common/CHANGES.txt

@@ -531,6 +531,8 @@ Release 2.5.0 - UNRELEASED
 
 
     HADOOP-10630. Possible race condition in RetryInvocationHandler. (jing9)
     HADOOP-10630. Possible race condition in RetryInvocationHandler. (jing9)
 
 
+    HADOOP-10658. SSLFactory expects truststores being configured. (tucu via atm)
+
 Release 2.4.1 - UNRELEASED
 Release 2.4.1 - UNRELEASED
 
 
   INCOMPATIBLE CHANGES
   INCOMPATIBLE CHANGES

+ 26 - 26
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/ssl/FileBasedKeyStoresFactory.java

@@ -188,33 +188,33 @@ public class FileBasedKeyStoresFactory implements KeyStoresFactory {
     String locationProperty =
     String locationProperty =
       resolvePropertyName(mode, SSL_TRUSTSTORE_LOCATION_TPL_KEY);
       resolvePropertyName(mode, SSL_TRUSTSTORE_LOCATION_TPL_KEY);
     String truststoreLocation = conf.get(locationProperty, "");
     String truststoreLocation = conf.get(locationProperty, "");
-    if (truststoreLocation.isEmpty()) {
-      throw new GeneralSecurityException("The property '" + locationProperty +
-        "' has not been set in the ssl configuration file.");
-    }
-
-    String passwordProperty = resolvePropertyName(mode,
-                                                  SSL_TRUSTSTORE_PASSWORD_TPL_KEY);
-    String truststorePassword = conf.get(passwordProperty, "");
-    if (truststorePassword.isEmpty()) {
-      throw new GeneralSecurityException("The property '" + passwordProperty +
-        "' has not been set in the ssl configuration file.");
+    if (!truststoreLocation.isEmpty()) {
+      String passwordProperty = resolvePropertyName(mode,
+          SSL_TRUSTSTORE_PASSWORD_TPL_KEY);
+      String truststorePassword = conf.get(passwordProperty, "");
+      if (truststorePassword.isEmpty()) {
+        throw new GeneralSecurityException("The property '" + passwordProperty +
+            "' has not been set in the ssl configuration file.");
+      }
+      long truststoreReloadInterval =
+          conf.getLong(
+              resolvePropertyName(mode, SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY),
+              DEFAULT_SSL_TRUSTSTORE_RELOAD_INTERVAL);
+
+      LOG.debug(mode.toString() + " TrustStore: " + truststoreLocation);
+
+      trustManager = new ReloadingX509TrustManager(truststoreType,
+          truststoreLocation,
+          truststorePassword,
+          truststoreReloadInterval);
+      trustManager.init();
+      LOG.debug(mode.toString() + " Loaded TrustStore: " + truststoreLocation);
+      trustManagers = new TrustManager[]{trustManager};
+    } else {
+      LOG.warn("The property '" + locationProperty + "' has not been set, " +
+          "no TrustStore will be loaded");
+      trustManagers = null;
     }
     }
-    long truststoreReloadInterval =
-      conf.getLong(
-        resolvePropertyName(mode, SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY),
-        DEFAULT_SSL_TRUSTSTORE_RELOAD_INTERVAL);
-
-    LOG.debug(mode.toString() + " TrustStore: " + truststoreLocation);
-
-    trustManager = new ReloadingX509TrustManager(truststoreType,
-                                                 truststoreLocation,
-                                                 truststorePassword,
-                                                 truststoreReloadInterval);
-    trustManager.init();
-    LOG.debug(mode.toString() + " Loaded TrustStore: " + truststoreLocation);
-
-    trustManagers = new TrustManager[]{trustManager};
   }
   }
 
 
   /**
   /**

+ 54 - 31
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/ssl/KeyStoreTestUtil.java

@@ -76,8 +76,8 @@ public class KeyStoreTestUtil {
    * @throws GeneralSecurityException thrown if an Security error ocurred.
    * @throws GeneralSecurityException thrown if an Security error ocurred.
    */
    */
   public static X509Certificate generateCertificate(String dn, KeyPair pair,
   public static X509Certificate generateCertificate(String dn, KeyPair pair,
-                                                    int days, String algorithm)
-    throws GeneralSecurityException, IOException {
+      int days, String algorithm)
+      throws GeneralSecurityException, IOException {
     PrivateKey privkey = pair.getPrivate();
     PrivateKey privkey = pair.getPrivate();
     X509CertInfo info = new X509CertInfo();
     X509CertInfo info = new X509CertInfo();
     Date from = new Date();
     Date from = new Date();
@@ -92,7 +92,7 @@ public class KeyStoreTestUtil {
     info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
     info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
     info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
     info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
     info
     info
-      .set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
+        .set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
     AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
     AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
     info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));
     info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));
 
 
@@ -103,30 +103,30 @@ public class KeyStoreTestUtil {
     // Update the algorith, and resign.
     // Update the algorith, and resign.
     algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG);
     algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG);
     info
     info
-      .set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM,
-           algo);
+        .set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM,
+            algo);
     cert = new X509CertImpl(info);
     cert = new X509CertImpl(info);
     cert.sign(privkey, algorithm);
     cert.sign(privkey, algorithm);
     return cert;
     return cert;
   }
   }
 
 
   public static KeyPair generateKeyPair(String algorithm)
   public static KeyPair generateKeyPair(String algorithm)
-    throws NoSuchAlgorithmException {
+      throws NoSuchAlgorithmException {
     KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
     KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
     keyGen.initialize(1024);
     keyGen.initialize(1024);
     return keyGen.genKeyPair();
     return keyGen.genKeyPair();
   }
   }
 
 
   private static KeyStore createEmptyKeyStore()
   private static KeyStore createEmptyKeyStore()
-    throws GeneralSecurityException, IOException {
+      throws GeneralSecurityException, IOException {
     KeyStore ks = KeyStore.getInstance("JKS");
     KeyStore ks = KeyStore.getInstance("JKS");
     ks.load(null, null); // initialize
     ks.load(null, null); // initialize
     return ks;
     return ks;
   }
   }
 
 
   private static void saveKeyStore(KeyStore ks, String filename,
   private static void saveKeyStore(KeyStore ks, String filename,
-                                   String password)
-    throws GeneralSecurityException, IOException {
+      String password)
+      throws GeneralSecurityException, IOException {
     FileOutputStream out = new FileOutputStream(filename);
     FileOutputStream out = new FileOutputStream(filename);
     try {
     try {
       ks.store(out, password.toCharArray());
       ks.store(out, password.toCharArray());
@@ -136,18 +136,18 @@ public class KeyStoreTestUtil {
   }
   }
 
 
   public static void createKeyStore(String filename,
   public static void createKeyStore(String filename,
-                                    String password, String alias,
-                                    Key privateKey, Certificate cert)
-    throws GeneralSecurityException, IOException {
+      String password, String alias,
+      Key privateKey, Certificate cert)
+      throws GeneralSecurityException, IOException {
     KeyStore ks = createEmptyKeyStore();
     KeyStore ks = createEmptyKeyStore();
     ks.setKeyEntry(alias, privateKey, password.toCharArray(),
     ks.setKeyEntry(alias, privateKey, password.toCharArray(),
-                   new Certificate[]{cert});
+        new Certificate[]{cert});
     saveKeyStore(ks, filename, password);
     saveKeyStore(ks, filename, password);
   }
   }
 
 
   /**
   /**
    * Creates a keystore with a single key and saves it to a file.
    * Creates a keystore with a single key and saves it to a file.
-   * 
+   *
    * @param filename String file to save
    * @param filename String file to save
    * @param password String store password to set on keystore
    * @param password String store password to set on keystore
    * @param keyPassword String key password to set on key
    * @param keyPassword String key password to set on key
@@ -158,27 +158,27 @@ public class KeyStoreTestUtil {
    * @throws IOException if there is an I/O error saving the file
    * @throws IOException if there is an I/O error saving the file
    */
    */
   public static void createKeyStore(String filename,
   public static void createKeyStore(String filename,
-                                    String password, String keyPassword, String alias,
-                                    Key privateKey, Certificate cert)
-    throws GeneralSecurityException, IOException {
+      String password, String keyPassword, String alias,
+      Key privateKey, Certificate cert)
+      throws GeneralSecurityException, IOException {
     KeyStore ks = createEmptyKeyStore();
     KeyStore ks = createEmptyKeyStore();
     ks.setKeyEntry(alias, privateKey, keyPassword.toCharArray(),
     ks.setKeyEntry(alias, privateKey, keyPassword.toCharArray(),
-                   new Certificate[]{cert});
+        new Certificate[]{cert});
     saveKeyStore(ks, filename, password);
     saveKeyStore(ks, filename, password);
   }
   }
 
 
   public static void createTrustStore(String filename,
   public static void createTrustStore(String filename,
-                                      String password, String alias,
-                                      Certificate cert)
-    throws GeneralSecurityException, IOException {
+      String password, String alias,
+      Certificate cert)
+      throws GeneralSecurityException, IOException {
     KeyStore ks = createEmptyKeyStore();
     KeyStore ks = createEmptyKeyStore();
     ks.setCertificateEntry(alias, cert);
     ks.setCertificateEntry(alias, cert);
     saveKeyStore(ks, filename, password);
     saveKeyStore(ks, filename, password);
   }
   }
 
 
   public static <T extends Certificate> void createTrustStore(
   public static <T extends Certificate> void createTrustStore(
-    String filename, String password, Map<String, T> certs)
-    throws GeneralSecurityException, IOException {
+      String filename, String password, Map<String, T> certs)
+      throws GeneralSecurityException, IOException {
     KeyStore ks = createEmptyKeyStore();
     KeyStore ks = createEmptyKeyStore();
     for (Map.Entry<String, T> cert : certs.entrySet()) {
     for (Map.Entry<String, T> cert : certs.entrySet()) {
       ks.setCertificateEntry(cert.getKey(), cert.getValue());
       ks.setCertificateEntry(cert.getKey(), cert.getValue());
@@ -187,7 +187,7 @@ public class KeyStoreTestUtil {
   }
   }
 
 
   public static void cleanupSSLConfig(String keystoresDir, String sslConfDir)
   public static void cleanupSSLConfig(String keystoresDir, String sslConfDir)
-    throws Exception {
+      throws Exception {
     File f = new File(keystoresDir + "/clientKS.jks");
     File f = new File(keystoresDir + "/clientKS.jks");
     f.delete();
     f.delete();
     f = new File(keystoresDir + "/serverKS.jks");
     f = new File(keystoresDir + "/serverKS.jks");
@@ -196,7 +196,7 @@ public class KeyStoreTestUtil {
     f.delete();
     f.delete();
     f = new File(sslConfDir + "/ssl-client.xml");
     f = new File(sslConfDir + "/ssl-client.xml");
     f.delete();
     f.delete();
-    f = new File(sslConfDir +  "/ssl-server.xml");
+    f = new File(sslConfDir + "/ssl-server.xml");
     f.delete();
     f.delete();
   }
   }
 
 
@@ -205,22 +205,42 @@ public class KeyStoreTestUtil {
    * SSLFactory.  This includes keys, certs, keystores, truststores, the server
    * SSLFactory.  This includes keys, certs, keystores, truststores, the server
    * SSL configuration file, the client SSL configuration file, and the master
    * SSL configuration file, the client SSL configuration file, and the master
    * configuration file read by the SSLFactory.
    * configuration file read by the SSLFactory.
-   * 
+   *
+   * @param keystoresDir String directory to save keystores
+   * @param sslConfDir String directory to save SSL configuration files
+   * @param conf Configuration master configuration to be used by an SSLFactory,
+   * which will be mutated by this method
+   * @param useClientCert boolean true to make the client present a cert in the
+   * SSL handshake
+   */
+  public static void setupSSLConfig(String keystoresDir, String sslConfDir,
+      Configuration conf, boolean useClientCert) throws Exception {
+    setupSSLConfig(keystoresDir, sslConfDir, conf, useClientCert, true);
+  }
+
+  /**
+   * Performs complete setup of SSL configuration in preparation for testing an
+   * SSLFactory.  This includes keys, certs, keystores, truststores, the server
+   * SSL configuration file, the client SSL configuration file, and the master
+   * configuration file read by the SSLFactory.
+   *
    * @param keystoresDir String directory to save keystores
    * @param keystoresDir String directory to save keystores
    * @param sslConfDir String directory to save SSL configuration files
    * @param sslConfDir String directory to save SSL configuration files
    * @param conf Configuration master configuration to be used by an SSLFactory,
    * @param conf Configuration master configuration to be used by an SSLFactory,
-   *   which will be mutated by this method
+   * which will be mutated by this method
    * @param useClientCert boolean true to make the client present a cert in the
    * @param useClientCert boolean true to make the client present a cert in the
-   *   SSL handshake
+   * SSL handshake
+   * @param trustStore boolean true to create truststore, false not to create it
    */
    */
   public static void setupSSLConfig(String keystoresDir, String sslConfDir,
   public static void setupSSLConfig(String keystoresDir, String sslConfDir,
-                                    Configuration conf, boolean useClientCert)
+                                    Configuration conf, boolean useClientCert,
+      boolean trustStore)
     throws Exception {
     throws Exception {
     String clientKS = keystoresDir + "/clientKS.jks";
     String clientKS = keystoresDir + "/clientKS.jks";
     String clientPassword = "clientP";
     String clientPassword = "clientP";
     String serverKS = keystoresDir + "/serverKS.jks";
     String serverKS = keystoresDir + "/serverKS.jks";
     String serverPassword = "serverP";
     String serverPassword = "serverP";
-    String trustKS = keystoresDir + "/trustKS.jks";
+    String trustKS = null;
     String trustPassword = "trustP";
     String trustPassword = "trustP";
 
 
     File sslClientConfFile = new File(sslConfDir + "/ssl-client.xml");
     File sslClientConfFile = new File(sslConfDir + "/ssl-client.xml");
@@ -246,7 +266,10 @@ public class KeyStoreTestUtil {
                                     sKP.getPrivate(), sCert);
                                     sKP.getPrivate(), sCert);
     certs.put("server", sCert);
     certs.put("server", sCert);
 
 
-    KeyStoreTestUtil.createTrustStore(trustKS, trustPassword, certs);
+    if (trustStore) {
+      trustKS = keystoresDir + "/trustKS.jks";
+      KeyStoreTestUtil.createTrustStore(trustKS, trustPassword, certs);
+    }
 
 
     Configuration clientSSLConf = createClientSSLConfig(clientKS, clientPassword,
     Configuration clientSSLConf = createClientSSLConfig(clientKS, clientPassword,
       clientPassword, trustKS);
       clientPassword, trustKS);

+ 21 - 8
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/ssl/TestSSLFactory.java

@@ -50,11 +50,12 @@ public class TestSSLFactory {
     base.mkdirs();
     base.mkdirs();
   }
   }
 
 
-  private Configuration createConfiguration(boolean clientCert)
+  private Configuration createConfiguration(boolean clientCert,
+      boolean trustStore)
     throws Exception {
     throws Exception {
     Configuration conf = new Configuration();
     Configuration conf = new Configuration();
     KeyStoreTestUtil.setupSSLConfig(KEYSTORES_DIR, sslConfsDir, conf,
     KeyStoreTestUtil.setupSSLConfig(KEYSTORES_DIR, sslConfsDir, conf,
-      clientCert);
+      clientCert, trustStore);
     return conf;
     return conf;
   }
   }
 
 
@@ -67,7 +68,7 @@ public class TestSSLFactory {
 
 
   @Test(expected = IllegalStateException.class)
   @Test(expected = IllegalStateException.class)
   public void clientMode() throws Exception {
   public void clientMode() throws Exception {
-    Configuration conf = createConfiguration(false);
+    Configuration conf = createConfiguration(false, true);
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
     try {
     try {
       sslFactory.init();
       sslFactory.init();
@@ -80,7 +81,7 @@ public class TestSSLFactory {
   }
   }
 
 
   private void serverMode(boolean clientCert, boolean socket) throws Exception {
   private void serverMode(boolean clientCert, boolean socket) throws Exception {
-    Configuration conf = createConfiguration(clientCert);
+    Configuration conf = createConfiguration(clientCert, true);
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.SERVER, conf);
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.SERVER, conf);
     try {
     try {
       sslFactory.init();
       sslFactory.init();
@@ -119,7 +120,7 @@ public class TestSSLFactory {
 
 
   @Test
   @Test
   public void validHostnameVerifier() throws Exception {
   public void validHostnameVerifier() throws Exception {
-    Configuration conf = createConfiguration(false);
+    Configuration conf = createConfiguration(false, true);
     conf.unset(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY);
     conf.unset(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY);
     SSLFactory sslFactory = new
     SSLFactory sslFactory = new
       SSLFactory(SSLFactory.Mode.CLIENT, conf);
       SSLFactory(SSLFactory.Mode.CLIENT, conf);
@@ -157,7 +158,7 @@ public class TestSSLFactory {
 
 
   @Test(expected = GeneralSecurityException.class)
   @Test(expected = GeneralSecurityException.class)
   public void invalidHostnameVerifier() throws Exception {
   public void invalidHostnameVerifier() throws Exception {
-    Configuration conf = createConfiguration(false);
+    Configuration conf = createConfiguration(false, true);
     conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "foo");
     conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "foo");
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
     try {
     try {
@@ -169,7 +170,7 @@ public class TestSSLFactory {
 
 
   @Test
   @Test
   public void testConnectionConfigurator() throws Exception {
   public void testConnectionConfigurator() throws Exception {
-    Configuration conf = createConfiguration(false);
+    Configuration conf = createConfiguration(false, true);
     conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "STRICT_IE6");
     conf.set(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "STRICT_IE6");
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
     try {
     try {
@@ -275,7 +276,7 @@ public class TestSSLFactory {
 
 
   @Test
   @Test
   public void testNoClientCertsInitialization() throws Exception {
   public void testNoClientCertsInitialization() throws Exception {
-    Configuration conf = createConfiguration(false);
+    Configuration conf = createConfiguration(false, true);
     conf.unset(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY);
     conf.unset(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY);
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
     SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
     try {
     try {
@@ -285,4 +286,16 @@ public class TestSSLFactory {
     }
     }
   }
   }
 
 
+  @Test
+  public void testNoTrustStore() throws Exception {
+    Configuration conf = createConfiguration(false, false);
+    conf.unset(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY);
+    SSLFactory sslFactory = new SSLFactory(SSLFactory.Mode.SERVER, conf);
+    try {
+      sslFactory.init();
+    } finally {
+      sslFactory.destroy();
+    }
+  }
+
 }
 }