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);