You are viewing a plain text version of this content. The canonical link for it is here.
Posted to yarn-commits@hadoop.apache.org by ji...@apache.org on 2014/08/12 20:29:42 UTC

svn commit: r1617555 - in /hadoop/common/trunk/hadoop-yarn-project: ./ hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/ hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/

Author: jianhe
Date: Tue Aug 12 18:29:42 2014
New Revision: 1617555

URL: http://svn.apache.org/r1617555
Log:
YARN-2373. Changed WebAppUtils to use Configuration#getPassword for accessing SSL passwords. Contributed by Larry McCay

Added:
    hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/
    hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java
Modified:
    hadoop/common/trunk/hadoop-yarn-project/CHANGES.txt
    hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java

Modified: hadoop/common/trunk/hadoop-yarn-project/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-yarn-project/CHANGES.txt?rev=1617555&r1=1617554&r2=1617555&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-yarn-project/CHANGES.txt (original)
+++ hadoop/common/trunk/hadoop-yarn-project/CHANGES.txt Tue Aug 12 18:29:42 2014
@@ -116,6 +116,9 @@ Release 2.6.0 - UNRELEASED
     YARN-2138. Cleaned up notifyDone* APIs in RMStateStore. (Varun Saxena via
     jianhe)
 
+    YARN-2373. Changed WebAppUtils to use Configuration#getPassword for
+    accessing SSL passwords. (Larry McCay via jianhe)
+
   OPTIMIZATIONS
 
   BUG FIXES

Modified: hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java?rev=1617555&r1=1617554&r2=1617555&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java (original)
+++ hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/webapp/util/WebAppUtils.java Tue Aug 12 18:29:42 2014
@@ -19,12 +19,12 @@ package org.apache.hadoop.yarn.webapp.ut
 
 import static org.apache.hadoop.yarn.util.StringHelper.PATH_JOINER;
 
+import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.hadoop.classification.InterfaceAudience.Private;
 import org.apache.hadoop.classification.InterfaceStability.Evolving;
@@ -40,6 +40,12 @@ import org.apache.hadoop.yarn.util.RMHAU
 @Private
 @Evolving
 public class WebAppUtils {
+  public static final String WEB_APP_TRUSTSTORE_PASSWORD_KEY =
+      "ssl.server.truststore.password";
+  public static final String WEB_APP_KEYSTORE_PASSWORD_KEY =
+      "ssl.server.keystore.password";
+  public static final String WEB_APP_KEY_PASSWORD_KEY =
+      "ssl.server.keystore.keypassword";
   public static final String HTTPS_PREFIX = "https://";
   public static final String HTTP_PREFIX = "http://";
 
@@ -274,21 +280,56 @@ public class WebAppUtils {
 
   /**
    * Load the SSL keystore / truststore into the HttpServer builder.
+   * @param builder the HttpServer2.Builder to populate with ssl config
    */
   public static HttpServer2.Builder loadSslConfiguration(
       HttpServer2.Builder builder) {
-    Configuration sslConf = new Configuration(false);
+    return loadSslConfiguration(builder, null);
+  }
+
+  /**
+   * Load the SSL keystore / truststore into the HttpServer builder.
+   * @param builder the HttpServer2.Builder to populate with ssl config
+   * @param sslConf the Configuration instance to use during loading of SSL conf
+   */
+  public static HttpServer2.Builder loadSslConfiguration(
+      HttpServer2.Builder builder, Configuration sslConf) {
+    if (sslConf == null) {
+      sslConf = new Configuration(false);
+    }
     boolean needsClientAuth = YarnConfiguration.YARN_SSL_CLIENT_HTTPS_NEED_AUTH_DEFAULT;
     sslConf.addResource(YarnConfiguration.YARN_SSL_SERVER_RESOURCE_DEFAULT);
 
     return builder
         .needsClientAuth(needsClientAuth)
-        .keyPassword(sslConf.get("ssl.server.keystore.keypassword"))
+        .keyPassword(getPassword(sslConf, WEB_APP_KEY_PASSWORD_KEY))
         .keyStore(sslConf.get("ssl.server.keystore.location"),
-            sslConf.get("ssl.server.keystore.password"),
+            getPassword(sslConf, WEB_APP_KEYSTORE_PASSWORD_KEY),
             sslConf.get("ssl.server.keystore.type", "jks"))
         .trustStore(sslConf.get("ssl.server.truststore.location"),
-            sslConf.get("ssl.server.truststore.password"),
+            getPassword(sslConf, WEB_APP_TRUSTSTORE_PASSWORD_KEY),
             sslConf.get("ssl.server.truststore.type", "jks"));
   }
+
+  /**
+   * Leverages the Configuration.getPassword method to attempt to get
+   * passwords from the CredentialProvider API before falling back to
+   * clear text in config - if falling back is allowed.
+   * @param conf Configuration instance
+   * @param alias name of the credential to retreive
+   * @return String credential value or null
+   */
+  static String getPassword(Configuration conf, String alias) {
+    String password = null;
+    try {
+      char[] passchars = conf.getPassword(alias);
+      if (passchars != null) {
+        password = new String(passchars);
+      }
+    }
+    catch (IOException ioe) {
+      password = null;
+    }
+    return password;
+  }
 }

Added: hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java?rev=1617555&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java (added)
+++ hadoop/common/trunk/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/webapp/util/TestWebAppUtils.java Tue Aug 12 18:29:42 2014
@@ -0,0 +1,148 @@
+/**
+* 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.hadoop.yarn.webapp.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.http.HttpServer2;
+import org.apache.hadoop.http.HttpServer2.Builder;
+import org.apache.hadoop.security.alias.CredentialProvider;
+import org.apache.hadoop.security.alias.CredentialProviderFactory;
+import org.apache.hadoop.security.alias.JavaKeyStoreProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestWebAppUtils {
+
+  @Test
+  public void testGetPassword() throws Exception {
+    Configuration conf = provisionCredentialsForSSL();
+
+    // use WebAppUtils as would be used by loadSslConfiguration
+    Assert.assertEquals("keypass",
+        WebAppUtils.getPassword(conf, WebAppUtils.WEB_APP_KEY_PASSWORD_KEY));
+    Assert.assertEquals("storepass",
+        WebAppUtils.getPassword(conf, WebAppUtils.WEB_APP_KEYSTORE_PASSWORD_KEY));
+    Assert.assertEquals("trustpass",
+        WebAppUtils.getPassword(conf, WebAppUtils.WEB_APP_TRUSTSTORE_PASSWORD_KEY));
+
+    // let's make sure that a password that doesn't exist returns null
+    Assert.assertEquals(null, WebAppUtils.getPassword(conf,"invalid-alias"));
+  }
+
+  @Test
+  public void testLoadSslConfiguration() throws Exception {
+    Configuration conf = provisionCredentialsForSSL();
+    TestBuilder builder = (TestBuilder) new TestBuilder();
+
+    builder = (TestBuilder) WebAppUtils.loadSslConfiguration(
+        builder, conf);
+
+    String keypass = "keypass";
+    String storepass = "storepass";
+    String trustpass = "trustpass";    
+
+    // make sure we get the right passwords in the builder
+    assertEquals(keypass, ((TestBuilder)builder).keypass);
+    assertEquals(storepass, ((TestBuilder)builder).keystorePassword);
+    assertEquals(trustpass, ((TestBuilder)builder).truststorePassword);
+  }
+
+  protected Configuration provisionCredentialsForSSL() throws IOException,
+      Exception {
+    File testDir = new File(System.getProperty("test.build.data",
+        "target/test-dir"));
+
+    Configuration conf = new Configuration();
+    final String ourUrl =
+    JavaKeyStoreProvider.SCHEME_NAME + "://file/" + testDir + "/test.jks";
+
+    File file = new File(testDir, "test.jks");
+    file.delete();
+    conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, ourUrl);
+
+    CredentialProvider provider =
+        CredentialProviderFactory.getProviders(conf).get(0);
+    char[] keypass = {'k', 'e', 'y', 'p', 'a', 's', 's'};
+    char[] storepass = {'s', 't', 'o', 'r', 'e', 'p', 'a', 's', 's'};
+    char[] trustpass = {'t', 'r', 'u', 's', 't', 'p', 'a', 's', 's'};
+
+    // ensure that we get nulls when the key isn't there
+    assertEquals(null, provider.getCredentialEntry(
+        WebAppUtils.WEB_APP_KEY_PASSWORD_KEY));
+    assertEquals(null, provider.getCredentialEntry(
+        WebAppUtils.WEB_APP_KEYSTORE_PASSWORD_KEY));
+    assertEquals(null, provider.getCredentialEntry(
+        WebAppUtils.WEB_APP_TRUSTSTORE_PASSWORD_KEY));
+
+    // create new aliases
+    try {
+      provider.createCredentialEntry(
+          WebAppUtils.WEB_APP_KEY_PASSWORD_KEY, keypass);
+
+      provider.createCredentialEntry(
+          WebAppUtils.WEB_APP_KEYSTORE_PASSWORD_KEY, storepass);
+
+      provider.createCredentialEntry(
+          WebAppUtils.WEB_APP_TRUSTSTORE_PASSWORD_KEY, trustpass);
+
+      // write out so that it can be found in checks
+      provider.flush();
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+    // make sure we get back the right key directly from api
+    assertArrayEquals(keypass, provider.getCredentialEntry(
+        WebAppUtils.WEB_APP_KEY_PASSWORD_KEY).getCredential());
+    assertArrayEquals(storepass, provider.getCredentialEntry(
+        WebAppUtils.WEB_APP_KEYSTORE_PASSWORD_KEY).getCredential());
+    assertArrayEquals(trustpass, provider.getCredentialEntry(
+        WebAppUtils.WEB_APP_TRUSTSTORE_PASSWORD_KEY).getCredential());
+    return conf;
+  }
+
+  public class TestBuilder extends HttpServer2.Builder {
+    public String keypass;
+    public String keystorePassword;
+    public String truststorePassword;
+
+    @Override
+    public Builder trustStore(String location, String password, String type) {
+      truststorePassword = password;
+      return super.trustStore(location, password, type);
+    }
+
+    @Override
+    public Builder keyStore(String location, String password, String type) {
+      keystorePassword = password;
+      return super.keyStore(location, password, type);
+    }
+
+    @Override
+    public Builder keyPassword(String password) {
+      keypass = password;
+      return super.keyPassword(password);
+    }
+  }
+}