You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ap...@apache.org on 2014/08/29 16:54:55 UTC

[1/2] git commit: HBASE-11810 Access SSL Passwords through Credential Provider API (Larry McCay)

Repository: hbase
Updated Branches:
  refs/heads/branch-1 d12ad1738 -> 51cf5c359
  refs/heads/master 8c0e5dca7 -> e5a5e968f


HBASE-11810 Access SSL Passwords through Credential Provider API (Larry McCay)


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

Branch: refs/heads/master
Commit: e5a5e968f16bdeae3b2b16657c2c7c54ea025579
Parents: 8c0e5dc
Author: Andrew Purtell <ap...@apache.org>
Authored: Thu Aug 28 16:18:11 2014 -0700
Committer: Andrew Purtell <ap...@apache.org>
Committed: Fri Aug 29 07:54:45 2014 -0700

----------------------------------------------------------------------
 .../apache/hadoop/hbase/HBaseConfiguration.java |  49 ++++
 .../hadoop/hbase/TestHBaseConfiguration.java    | 275 ++++++++++++++++++-
 .../apache/hadoop/hbase/rest/RESTServer.java    |   6 +-
 3 files changed, 327 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/e5a5e968/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java
index 9a0b38b..1cb992e 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java
@@ -17,6 +17,9 @@
  */
 package org.apache.hadoop.hbase;
 
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Map.Entry;
 
 import org.apache.commons.logging.Log;
@@ -160,6 +163,52 @@ public class HBaseConfiguration extends Configuration {
     }
   }
 
+  /**
+   * Get the password from the Configuration instance using the
+   * getPassword method if it exists. If not, then fall back to the
+   * general get method for configuration elements.
+   * @param conf configuration instance for accessing the passwords
+   * @param alias the name of the password element
+   * @param defPass the default password
+   * @return String password or default password
+   * @throws IOException
+   */
+  public static String getPassword(Configuration conf, String alias,
+      String defPass) throws IOException {
+    String passwd = null;
+    try {
+      Method m = Configuration.class.getMethod("getPassword", String.class);
+      char[] p = (char[]) m.invoke(conf, alias);
+      if (p != null) {
+        LOG.debug(String.format("Config option \"%s\" was found through" +
+        		" the Configuration getPassword method.", alias));
+        passwd = new String(p);
+      }
+      else {
+        LOG.debug(String.format(
+            "Config option \"%s\" was not found. Using provided default value",
+            alias));
+        passwd = defPass;
+      }
+    } catch (NoSuchMethodException e) {
+      // this is a version of Hadoop where the credential
+      //provider API doesn't exist yet
+      LOG.debug(String.format(
+          "Credential.getPassword method is not available." +
+          " Falling back to configuration."));
+      passwd = conf.get(alias, defPass);
+    } catch (SecurityException e) {
+      throw new IOException(e.getMessage(), e);
+    } catch (IllegalAccessException e) {
+      throw new IOException(e.getMessage(), e);
+    } catch (IllegalArgumentException e) {
+      throw new IOException(e.getMessage(), e);
+    } catch (InvocationTargetException e) {
+      throw new IOException(e.getMessage(), e);
+    }
+    return passwd;
+  }
+
   /** For debugging.  Dump configurations to system output as xml format.
    * Master and RS configurations can also be dumped using
    * http services. e.g. "curl http://master:16010/dump"

http://git-wip-us.apache.org/repos/asf/hbase/blob/e5a5e968/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java
index 94eac02..60fa3b3 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java
@@ -18,9 +18,16 @@
 
 package org.apache.hadoop.hbase;
 
-
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -28,6 +35,8 @@ import org.junit.experimental.categories.Category;
 @Category(SmallTests.class)
 public class TestHBaseConfiguration {
 
+  private static final Log LOG = LogFactory.getLog(TestHBaseConfiguration.class);
+
   @Test
   public void testGetIntDeprecated() {
     int VAL = 1, VAL2 = 2;
@@ -53,4 +62,268 @@ public class TestHBaseConfiguration {
     assertEquals(VAL, HBaseConfiguration.getInt(conf, NAME, DEPRECATED_NAME, 0));
   }
 
+  @Test
+  public void testGetPassword() throws Exception {
+    Configuration conf = HBaseConfiguration.create();
+    conf.set(ReflectiveCredentialProviderClient.CREDENTIAL_PROVIDER_PATH,
+        "jceks://file/tmp/foo.jks");
+    ReflectiveCredentialProviderClient client =
+        new ReflectiveCredentialProviderClient();
+    if (client.isHadoopCredentialProviderAvailable()) {
+      char[] keyPass = {'k', 'e', 'y', 'p', 'a', 's', 's'};
+      char[] storePass = {'s', 't', 'o', 'r', 'e', 'p', 'a', 's', 's'};
+      client.createEntry(conf, "ssl.keypass.alias", keyPass);
+      client.createEntry(conf, "ssl.storepass.alias", storePass);
+
+      String keypass = HBaseConfiguration.getPassword(
+          conf, "ssl.keypass.alias", null);
+      assertEquals(keypass, new String(keyPass));
+
+      String storepass = HBaseConfiguration.getPassword(
+          conf, "ssl.storepass.alias", null);
+      assertEquals(storepass, new String(storePass));
+    }
+  }
+
+  private static class ReflectiveCredentialProviderClient {
+    public static final String HADOOP_CRED_PROVIDER_FACTORY_CLASS_NAME =
+        "org.apache.hadoop.security.alias.JavaKeyStoreProvider$Factory";
+    public static final String
+      HADOOP_CRED_PROVIDER_FACTORY_GET_PROVIDERS_METHOD_NAME = "getProviders";
+
+    public static final String HADOOP_CRED_PROVIDER_CLASS_NAME =
+        "org.apache.hadoop.security.alias.CredentialProvider";
+    public static final String
+        HADOOP_CRED_PROVIDER_GET_CREDENTIAL_ENTRY_METHOD_NAME =
+        "getCredentialEntry";
+    public static final String
+        HADOOP_CRED_PROVIDER_GET_ALIASES_METHOD_NAME = "getAliases";
+    public static final String
+        HADOOP_CRED_PROVIDER_CREATE_CREDENTIAL_ENTRY_METHOD_NAME =
+        "createCredentialEntry";
+    public static final String HADOOP_CRED_PROVIDER_FLUSH_METHOD_NAME = "flush";
+
+    public static final String HADOOP_CRED_ENTRY_CLASS_NAME =
+        "org.apache.hadoop.security.alias.CredentialProvider$CredentialEntry";
+    public static final String HADOOP_CRED_ENTRY_GET_CREDENTIAL_METHOD_NAME =
+        "getCredential";
+
+    public static final String CREDENTIAL_PROVIDER_PATH =
+        "hadoop.security.credential.provider.path";
+
+    private static Object hadoopCredProviderFactory = null;
+    private static Method getProvidersMethod = null;
+    private static Method getAliasesMethod = null;
+    private static Method getCredentialEntryMethod = null;
+    private static Method getCredentialMethod = null;
+    private static Method createCredentialEntryMethod = null;
+    private static Method flushMethod = null;
+    private static Boolean hadoopClassesAvailable = null;
+
+    /**
+     * Determine if we can load the necessary CredentialProvider classes. Only
+     * loaded the first time, so subsequent invocations of this method should
+     * return fast.
+     *
+     * @return True if the CredentialProvider classes/methods are available,
+     *         false otherwise.
+     */
+    private boolean isHadoopCredentialProviderAvailable() {
+      if (null != hadoopClassesAvailable) {
+        // Make sure everything is initialized as expected
+        if (hadoopClassesAvailable && null != getProvidersMethod
+            && null != hadoopCredProviderFactory
+            && null != getCredentialEntryMethod && null != getCredentialMethod) {
+          return true;
+        } else {
+          // Otherwise we failed to load it
+          return false;
+        }
+      }
+
+      hadoopClassesAvailable = false;
+
+      // Load Hadoop CredentialProviderFactory
+      Class<?> hadoopCredProviderFactoryClz = null;
+      try {
+        hadoopCredProviderFactoryClz = Class
+            .forName(HADOOP_CRED_PROVIDER_FACTORY_CLASS_NAME);
+      } catch (ClassNotFoundException e) {
+        return false;
+      }
+      // Instantiate Hadoop CredentialProviderFactory
+      try {
+        hadoopCredProviderFactory = hadoopCredProviderFactoryClz.newInstance();
+      } catch (InstantiationException e) {
+        return false;
+      } catch (IllegalAccessException e) {
+        return false;
+      }
+
+      try {
+        getProvidersMethod = loadMethod(hadoopCredProviderFactoryClz,
+            HADOOP_CRED_PROVIDER_FACTORY_GET_PROVIDERS_METHOD_NAME,
+            Configuration.class);
+
+        // Load Hadoop CredentialProvider
+        Class<?> hadoopCredProviderClz = null;
+        hadoopCredProviderClz = Class.forName(HADOOP_CRED_PROVIDER_CLASS_NAME);
+        getCredentialEntryMethod = loadMethod(hadoopCredProviderClz,
+            HADOOP_CRED_PROVIDER_GET_CREDENTIAL_ENTRY_METHOD_NAME, String.class);
+
+        getAliasesMethod = loadMethod(hadoopCredProviderClz,
+            HADOOP_CRED_PROVIDER_GET_ALIASES_METHOD_NAME);
+
+        createCredentialEntryMethod = loadMethod(hadoopCredProviderClz,
+            HADOOP_CRED_PROVIDER_CREATE_CREDENTIAL_ENTRY_METHOD_NAME,
+            String.class, char[].class);
+
+        flushMethod = loadMethod(hadoopCredProviderClz,
+            HADOOP_CRED_PROVIDER_FLUSH_METHOD_NAME);
+
+        // Load Hadoop CredentialEntry
+        Class<?> hadoopCredentialEntryClz = null;
+        try {
+          hadoopCredentialEntryClz = Class
+              .forName(HADOOP_CRED_ENTRY_CLASS_NAME);
+        } catch (ClassNotFoundException e) {
+          LOG.error("Failed to load class:" + e);
+          return false;
+        }
+
+        getCredentialMethod = loadMethod(hadoopCredentialEntryClz,
+            HADOOP_CRED_ENTRY_GET_CREDENTIAL_METHOD_NAME);
+      } catch (Exception e1) {
+        return false;
+      }
+
+      hadoopClassesAvailable = true;
+      LOG.info("Credential provider classes have been" +
+      		" loaded and initialized successfully through reflection.");
+      return true;
+
+    }
+
+    private Method loadMethod(Class<?> clz, String name, Class<?>... classes)
+        throws Exception {
+      Method method = null;
+      try {
+        method = clz.getMethod(name, classes);
+      } catch (SecurityException e) {
+        fail("security exception caught for: " + name + " in " +
+      clz.getCanonicalName());
+        throw e;
+      } catch (NoSuchMethodException e) {
+        LOG.error("Failed to load the " + name + ": " + e);
+        fail("no such method: " + name + " in " + clz.getCanonicalName());
+        throw e;
+      }
+      return method;
+    }
+
+    /**
+     * Wrapper to fetch the configured {@code List<CredentialProvider>}s.
+     *
+     * @param conf
+     *    Configuration with GENERAL_SECURITY_CREDENTIAL_PROVIDER_PATHS defined
+     * @return List of CredentialProviders, or null if they could not be loaded
+     */
+    @SuppressWarnings("unchecked")
+    protected  List<Object> getCredentialProviders(Configuration conf) {
+      // Call CredentialProviderFactory.getProviders(Configuration)
+      Object providersObj = null;
+      try {
+        providersObj = getProvidersMethod.invoke(hadoopCredProviderFactory,
+            conf);
+      } catch (IllegalArgumentException e) {
+        LOG.error("Failed to invoke: " + getProvidersMethod.getName() +
+            ": " + e);
+        return null;
+      } catch (IllegalAccessException e) {
+        LOG.error("Failed to invoke: " + getProvidersMethod.getName() +
+            ": " + e);
+        return null;
+      } catch (InvocationTargetException e) {
+        LOG.error("Failed to invoke: " + getProvidersMethod.getName() +
+            ": " + e);
+        return null;
+      }
+
+      // Cast the Object to List<Object> (actually List<CredentialProvider>)
+      try {
+        return (List<Object>) providersObj;
+      } catch (ClassCastException e) {
+        return null;
+      }
+    }
+
+    /**
+     * Create a CredentialEntry using the configured Providers.
+     * If multiple CredentialProviders are configured, the first will be used.
+     *
+     * @param conf
+     *          Configuration for the CredentialProvider
+     * @param name
+     *          CredentialEntry name (alias)
+     * @param credential
+     *          The credential
+     */
+    public  void createEntry(Configuration conf, String name, char[] credential)
+        throws Exception {
+
+      if (!isHadoopCredentialProviderAvailable()) {
+        return;
+      }
+
+      List<Object> providers = getCredentialProviders(conf);
+      if (null == providers) {
+        throw new IOException("Could not fetch any CredentialProviders, " +
+        		"is the implementation available?");
+      }
+
+      Object provider = providers.get(0);
+      createEntryInProvider(provider, name, credential);
+    }
+
+    /**
+     * Create a CredentialEntry with the give name and credential in the
+     * credentialProvider. The credentialProvider argument must be an instance
+     * of Hadoop
+     * CredentialProvider.
+     *
+     * @param credentialProvider
+     *          Instance of CredentialProvider
+     * @param name
+     *          CredentialEntry name (alias)
+     * @param credential
+     *          The credential to store
+     */
+    private void createEntryInProvider(Object credentialProvider,
+        String name, char[] credential) throws Exception {
+
+      if (!isHadoopCredentialProviderAvailable()) {
+        return;
+      }
+
+      try {
+        createCredentialEntryMethod.invoke(credentialProvider, name, credential);
+      } catch (IllegalArgumentException e) {
+        return;
+      } catch (IllegalAccessException e) {
+        return;
+      } catch (InvocationTargetException e) {
+        return;
+      }
+
+      try {
+        flushMethod.invoke(credentialProvider);
+      } catch (IllegalArgumentException e) {
+        throw e;
+      } catch (IllegalAccessException e) {
+        throw e;
+      } catch (InvocationTargetException e) {
+        throw e;
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/e5a5e968/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java
index e6f13d6..64faa14 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java
@@ -191,8 +191,10 @@ public class RESTServer implements Constants {
     if(conf.getBoolean(REST_SSL_ENABLED, false)) {
       SslSelectChannelConnector sslConnector = new SslSelectChannelConnector();
       String keystore = conf.get(REST_SSL_KEYSTORE_STORE);
-      String password = conf.get(REST_SSL_KEYSTORE_PASSWORD);
-      String keyPassword = conf.get(REST_SSL_KEYSTORE_KEYPASSWORD, password);
+      String password = HBaseConfiguration.getPassword(conf,
+        REST_SSL_KEYSTORE_PASSWORD, null);
+      String keyPassword = HBaseConfiguration.getPassword(conf,
+        REST_SSL_KEYSTORE_KEYPASSWORD, password);
       sslConnector.setKeystore(keystore);
       sslConnector.setPassword(password);
       sslConnector.setKeyPassword(keyPassword);


[2/2] git commit: HBASE-11810 Access SSL Passwords through Credential Provider API (Larry McCay)

Posted by ap...@apache.org.
HBASE-11810 Access SSL Passwords through Credential Provider API (Larry McCay)


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/51cf5c35
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/51cf5c35
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/51cf5c35

Branch: refs/heads/branch-1
Commit: 51cf5c359b47a43780f86e5302128dd5bc324620
Parents: d12ad17
Author: Andrew Purtell <ap...@apache.org>
Authored: Thu Aug 28 16:18:11 2014 -0700
Committer: Andrew Purtell <ap...@apache.org>
Committed: Fri Aug 29 07:54:52 2014 -0700

----------------------------------------------------------------------
 .../apache/hadoop/hbase/HBaseConfiguration.java |  49 ++++
 .../hadoop/hbase/TestHBaseConfiguration.java    | 275 ++++++++++++++++++-
 .../apache/hadoop/hbase/rest/RESTServer.java    |   6 +-
 3 files changed, 327 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/51cf5c35/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java
index 9a0b38b..1cb992e 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HBaseConfiguration.java
@@ -17,6 +17,9 @@
  */
 package org.apache.hadoop.hbase;
 
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Map.Entry;
 
 import org.apache.commons.logging.Log;
@@ -160,6 +163,52 @@ public class HBaseConfiguration extends Configuration {
     }
   }
 
+  /**
+   * Get the password from the Configuration instance using the
+   * getPassword method if it exists. If not, then fall back to the
+   * general get method for configuration elements.
+   * @param conf configuration instance for accessing the passwords
+   * @param alias the name of the password element
+   * @param defPass the default password
+   * @return String password or default password
+   * @throws IOException
+   */
+  public static String getPassword(Configuration conf, String alias,
+      String defPass) throws IOException {
+    String passwd = null;
+    try {
+      Method m = Configuration.class.getMethod("getPassword", String.class);
+      char[] p = (char[]) m.invoke(conf, alias);
+      if (p != null) {
+        LOG.debug(String.format("Config option \"%s\" was found through" +
+        		" the Configuration getPassword method.", alias));
+        passwd = new String(p);
+      }
+      else {
+        LOG.debug(String.format(
+            "Config option \"%s\" was not found. Using provided default value",
+            alias));
+        passwd = defPass;
+      }
+    } catch (NoSuchMethodException e) {
+      // this is a version of Hadoop where the credential
+      //provider API doesn't exist yet
+      LOG.debug(String.format(
+          "Credential.getPassword method is not available." +
+          " Falling back to configuration."));
+      passwd = conf.get(alias, defPass);
+    } catch (SecurityException e) {
+      throw new IOException(e.getMessage(), e);
+    } catch (IllegalAccessException e) {
+      throw new IOException(e.getMessage(), e);
+    } catch (IllegalArgumentException e) {
+      throw new IOException(e.getMessage(), e);
+    } catch (InvocationTargetException e) {
+      throw new IOException(e.getMessage(), e);
+    }
+    return passwd;
+  }
+
   /** For debugging.  Dump configurations to system output as xml format.
    * Master and RS configurations can also be dumped using
    * http services. e.g. "curl http://master:16010/dump"

http://git-wip-us.apache.org/repos/asf/hbase/blob/51cf5c35/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java
----------------------------------------------------------------------
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java
index 94eac02..60fa3b3 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/TestHBaseConfiguration.java
@@ -18,9 +18,16 @@
 
 package org.apache.hadoop.hbase;
 
-
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -28,6 +35,8 @@ import org.junit.experimental.categories.Category;
 @Category(SmallTests.class)
 public class TestHBaseConfiguration {
 
+  private static final Log LOG = LogFactory.getLog(TestHBaseConfiguration.class);
+
   @Test
   public void testGetIntDeprecated() {
     int VAL = 1, VAL2 = 2;
@@ -53,4 +62,268 @@ public class TestHBaseConfiguration {
     assertEquals(VAL, HBaseConfiguration.getInt(conf, NAME, DEPRECATED_NAME, 0));
   }
 
+  @Test
+  public void testGetPassword() throws Exception {
+    Configuration conf = HBaseConfiguration.create();
+    conf.set(ReflectiveCredentialProviderClient.CREDENTIAL_PROVIDER_PATH,
+        "jceks://file/tmp/foo.jks");
+    ReflectiveCredentialProviderClient client =
+        new ReflectiveCredentialProviderClient();
+    if (client.isHadoopCredentialProviderAvailable()) {
+      char[] keyPass = {'k', 'e', 'y', 'p', 'a', 's', 's'};
+      char[] storePass = {'s', 't', 'o', 'r', 'e', 'p', 'a', 's', 's'};
+      client.createEntry(conf, "ssl.keypass.alias", keyPass);
+      client.createEntry(conf, "ssl.storepass.alias", storePass);
+
+      String keypass = HBaseConfiguration.getPassword(
+          conf, "ssl.keypass.alias", null);
+      assertEquals(keypass, new String(keyPass));
+
+      String storepass = HBaseConfiguration.getPassword(
+          conf, "ssl.storepass.alias", null);
+      assertEquals(storepass, new String(storePass));
+    }
+  }
+
+  private static class ReflectiveCredentialProviderClient {
+    public static final String HADOOP_CRED_PROVIDER_FACTORY_CLASS_NAME =
+        "org.apache.hadoop.security.alias.JavaKeyStoreProvider$Factory";
+    public static final String
+      HADOOP_CRED_PROVIDER_FACTORY_GET_PROVIDERS_METHOD_NAME = "getProviders";
+
+    public static final String HADOOP_CRED_PROVIDER_CLASS_NAME =
+        "org.apache.hadoop.security.alias.CredentialProvider";
+    public static final String
+        HADOOP_CRED_PROVIDER_GET_CREDENTIAL_ENTRY_METHOD_NAME =
+        "getCredentialEntry";
+    public static final String
+        HADOOP_CRED_PROVIDER_GET_ALIASES_METHOD_NAME = "getAliases";
+    public static final String
+        HADOOP_CRED_PROVIDER_CREATE_CREDENTIAL_ENTRY_METHOD_NAME =
+        "createCredentialEntry";
+    public static final String HADOOP_CRED_PROVIDER_FLUSH_METHOD_NAME = "flush";
+
+    public static final String HADOOP_CRED_ENTRY_CLASS_NAME =
+        "org.apache.hadoop.security.alias.CredentialProvider$CredentialEntry";
+    public static final String HADOOP_CRED_ENTRY_GET_CREDENTIAL_METHOD_NAME =
+        "getCredential";
+
+    public static final String CREDENTIAL_PROVIDER_PATH =
+        "hadoop.security.credential.provider.path";
+
+    private static Object hadoopCredProviderFactory = null;
+    private static Method getProvidersMethod = null;
+    private static Method getAliasesMethod = null;
+    private static Method getCredentialEntryMethod = null;
+    private static Method getCredentialMethod = null;
+    private static Method createCredentialEntryMethod = null;
+    private static Method flushMethod = null;
+    private static Boolean hadoopClassesAvailable = null;
+
+    /**
+     * Determine if we can load the necessary CredentialProvider classes. Only
+     * loaded the first time, so subsequent invocations of this method should
+     * return fast.
+     *
+     * @return True if the CredentialProvider classes/methods are available,
+     *         false otherwise.
+     */
+    private boolean isHadoopCredentialProviderAvailable() {
+      if (null != hadoopClassesAvailable) {
+        // Make sure everything is initialized as expected
+        if (hadoopClassesAvailable && null != getProvidersMethod
+            && null != hadoopCredProviderFactory
+            && null != getCredentialEntryMethod && null != getCredentialMethod) {
+          return true;
+        } else {
+          // Otherwise we failed to load it
+          return false;
+        }
+      }
+
+      hadoopClassesAvailable = false;
+
+      // Load Hadoop CredentialProviderFactory
+      Class<?> hadoopCredProviderFactoryClz = null;
+      try {
+        hadoopCredProviderFactoryClz = Class
+            .forName(HADOOP_CRED_PROVIDER_FACTORY_CLASS_NAME);
+      } catch (ClassNotFoundException e) {
+        return false;
+      }
+      // Instantiate Hadoop CredentialProviderFactory
+      try {
+        hadoopCredProviderFactory = hadoopCredProviderFactoryClz.newInstance();
+      } catch (InstantiationException e) {
+        return false;
+      } catch (IllegalAccessException e) {
+        return false;
+      }
+
+      try {
+        getProvidersMethod = loadMethod(hadoopCredProviderFactoryClz,
+            HADOOP_CRED_PROVIDER_FACTORY_GET_PROVIDERS_METHOD_NAME,
+            Configuration.class);
+
+        // Load Hadoop CredentialProvider
+        Class<?> hadoopCredProviderClz = null;
+        hadoopCredProviderClz = Class.forName(HADOOP_CRED_PROVIDER_CLASS_NAME);
+        getCredentialEntryMethod = loadMethod(hadoopCredProviderClz,
+            HADOOP_CRED_PROVIDER_GET_CREDENTIAL_ENTRY_METHOD_NAME, String.class);
+
+        getAliasesMethod = loadMethod(hadoopCredProviderClz,
+            HADOOP_CRED_PROVIDER_GET_ALIASES_METHOD_NAME);
+
+        createCredentialEntryMethod = loadMethod(hadoopCredProviderClz,
+            HADOOP_CRED_PROVIDER_CREATE_CREDENTIAL_ENTRY_METHOD_NAME,
+            String.class, char[].class);
+
+        flushMethod = loadMethod(hadoopCredProviderClz,
+            HADOOP_CRED_PROVIDER_FLUSH_METHOD_NAME);
+
+        // Load Hadoop CredentialEntry
+        Class<?> hadoopCredentialEntryClz = null;
+        try {
+          hadoopCredentialEntryClz = Class
+              .forName(HADOOP_CRED_ENTRY_CLASS_NAME);
+        } catch (ClassNotFoundException e) {
+          LOG.error("Failed to load class:" + e);
+          return false;
+        }
+
+        getCredentialMethod = loadMethod(hadoopCredentialEntryClz,
+            HADOOP_CRED_ENTRY_GET_CREDENTIAL_METHOD_NAME);
+      } catch (Exception e1) {
+        return false;
+      }
+
+      hadoopClassesAvailable = true;
+      LOG.info("Credential provider classes have been" +
+      		" loaded and initialized successfully through reflection.");
+      return true;
+
+    }
+
+    private Method loadMethod(Class<?> clz, String name, Class<?>... classes)
+        throws Exception {
+      Method method = null;
+      try {
+        method = clz.getMethod(name, classes);
+      } catch (SecurityException e) {
+        fail("security exception caught for: " + name + " in " +
+      clz.getCanonicalName());
+        throw e;
+      } catch (NoSuchMethodException e) {
+        LOG.error("Failed to load the " + name + ": " + e);
+        fail("no such method: " + name + " in " + clz.getCanonicalName());
+        throw e;
+      }
+      return method;
+    }
+
+    /**
+     * Wrapper to fetch the configured {@code List<CredentialProvider>}s.
+     *
+     * @param conf
+     *    Configuration with GENERAL_SECURITY_CREDENTIAL_PROVIDER_PATHS defined
+     * @return List of CredentialProviders, or null if they could not be loaded
+     */
+    @SuppressWarnings("unchecked")
+    protected  List<Object> getCredentialProviders(Configuration conf) {
+      // Call CredentialProviderFactory.getProviders(Configuration)
+      Object providersObj = null;
+      try {
+        providersObj = getProvidersMethod.invoke(hadoopCredProviderFactory,
+            conf);
+      } catch (IllegalArgumentException e) {
+        LOG.error("Failed to invoke: " + getProvidersMethod.getName() +
+            ": " + e);
+        return null;
+      } catch (IllegalAccessException e) {
+        LOG.error("Failed to invoke: " + getProvidersMethod.getName() +
+            ": " + e);
+        return null;
+      } catch (InvocationTargetException e) {
+        LOG.error("Failed to invoke: " + getProvidersMethod.getName() +
+            ": " + e);
+        return null;
+      }
+
+      // Cast the Object to List<Object> (actually List<CredentialProvider>)
+      try {
+        return (List<Object>) providersObj;
+      } catch (ClassCastException e) {
+        return null;
+      }
+    }
+
+    /**
+     * Create a CredentialEntry using the configured Providers.
+     * If multiple CredentialProviders are configured, the first will be used.
+     *
+     * @param conf
+     *          Configuration for the CredentialProvider
+     * @param name
+     *          CredentialEntry name (alias)
+     * @param credential
+     *          The credential
+     */
+    public  void createEntry(Configuration conf, String name, char[] credential)
+        throws Exception {
+
+      if (!isHadoopCredentialProviderAvailable()) {
+        return;
+      }
+
+      List<Object> providers = getCredentialProviders(conf);
+      if (null == providers) {
+        throw new IOException("Could not fetch any CredentialProviders, " +
+        		"is the implementation available?");
+      }
+
+      Object provider = providers.get(0);
+      createEntryInProvider(provider, name, credential);
+    }
+
+    /**
+     * Create a CredentialEntry with the give name and credential in the
+     * credentialProvider. The credentialProvider argument must be an instance
+     * of Hadoop
+     * CredentialProvider.
+     *
+     * @param credentialProvider
+     *          Instance of CredentialProvider
+     * @param name
+     *          CredentialEntry name (alias)
+     * @param credential
+     *          The credential to store
+     */
+    private void createEntryInProvider(Object credentialProvider,
+        String name, char[] credential) throws Exception {
+
+      if (!isHadoopCredentialProviderAvailable()) {
+        return;
+      }
+
+      try {
+        createCredentialEntryMethod.invoke(credentialProvider, name, credential);
+      } catch (IllegalArgumentException e) {
+        return;
+      } catch (IllegalAccessException e) {
+        return;
+      } catch (InvocationTargetException e) {
+        return;
+      }
+
+      try {
+        flushMethod.invoke(credentialProvider);
+      } catch (IllegalArgumentException e) {
+        throw e;
+      } catch (IllegalAccessException e) {
+        throw e;
+      } catch (InvocationTargetException e) {
+        throw e;
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/51cf5c35/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java
index e6f13d6..64faa14 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/RESTServer.java
@@ -191,8 +191,10 @@ public class RESTServer implements Constants {
     if(conf.getBoolean(REST_SSL_ENABLED, false)) {
       SslSelectChannelConnector sslConnector = new SslSelectChannelConnector();
       String keystore = conf.get(REST_SSL_KEYSTORE_STORE);
-      String password = conf.get(REST_SSL_KEYSTORE_PASSWORD);
-      String keyPassword = conf.get(REST_SSL_KEYSTORE_KEYPASSWORD, password);
+      String password = HBaseConfiguration.getPassword(conf,
+        REST_SSL_KEYSTORE_PASSWORD, null);
+      String keyPassword = HBaseConfiguration.getPassword(conf,
+        REST_SSL_KEYSTORE_KEYPASSWORD, password);
       sslConnector.setKeystore(keystore);
       sslConnector.setPassword(password);
       sslConnector.setKeyPassword(keyPassword);