diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java index 83eb5ad8bc..f24009d40d 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java @@ -149,6 +149,10 @@ public class LdapGroupsMapping public static final String BIND_PASSWORD_FILE_KEY = BIND_PASSWORD_KEY + ".file"; public static final String BIND_PASSWORD_FILE_DEFAULT = ""; + public static final String BIND_PASSWORD_ALIAS_KEY = + BIND_PASSWORD_KEY + ".alias"; + public static final String BIND_PASSWORD_ALIAS_DEFAULT = ""; + /* * Base distinguished name to use for searches */ @@ -662,12 +666,19 @@ public synchronized void setConf(Configuration conf) { } bindUser = conf.get(BIND_USER_KEY, BIND_USER_DEFAULT); - bindPassword = getPassword(conf, BIND_PASSWORD_KEY, BIND_PASSWORD_DEFAULT); + + String alias = conf.get(BIND_PASSWORD_ALIAS_KEY, + BIND_PASSWORD_ALIAS_DEFAULT); + bindPassword = getPasswordFromCredentialProviders(conf, alias, ""); if (bindPassword.isEmpty()) { - bindPassword = extractPassword( - conf.get(BIND_PASSWORD_FILE_KEY, BIND_PASSWORD_FILE_DEFAULT)); + bindPassword = getPassword(conf, BIND_PASSWORD_KEY, + BIND_PASSWORD_DEFAULT); + if (bindPassword.isEmpty()) { + bindPassword = extractPassword( + conf.get(BIND_PASSWORD_FILE_KEY, BIND_PASSWORD_FILE_DEFAULT)); + } } - + String baseDN = conf.getTrimmed(BASE_DN_KEY, BASE_DN_DEFAULT); // User search base which defaults to base dn. @@ -755,10 +766,10 @@ private void loadSslConf(Configuration sslConf) { } String getPasswordFromCredentialProviders( - Configuration conf, String alias, String defaultPass) { + Configuration config, String alias, String defaultPass) { String password = defaultPass; try { - char[] passchars = conf.getPasswordFromCredentialProviders(alias); + char[] passchars = config.getPasswordFromCredentialProviders(alias); if (passchars != null) { password = new String(passchars); } diff --git a/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml b/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml index 28e910ba26..f7d61c6d01 100644 --- a/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml +++ b/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml @@ -370,6 +370,16 @@ + + hadoop.security.group.mapping.ldap.bind.password.alias + + + The alias of the bind user to be used to get the password from credential + providers. If the alias is empty, property + hadoop.security.group.mapping.ldap.bind.password is used instead. + + + hadoop.security.group.mapping.ldap.bind.password.file diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java index a361d04a72..174333859b 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java @@ -300,13 +300,53 @@ public void testConfGetPassword() throws Exception { mapping.getPassword(conf, LdapGroupsMapping.BIND_PASSWORD_KEY, "")); Assert.assertEquals("storepass", mapping.getPassword(conf, LdapGroupsMapping.LDAP_KEYSTORE_PASSWORD_KEY, - "")); + "")); // let's make sure that a password that doesn't exist returns an // empty string as currently expected and used to trigger a call to // extract password Assert.assertEquals("", mapping.getPassword(conf,"invalid-alias", "")); } + @Test + public void testConfGetPasswordUsingAlias() throws Exception { + File testDir = GenericTestUtils.getTestDir(); + Configuration conf = getBaseConf(); + final Path jksPath = new Path(testDir.toString(), "test.jks"); + final String ourUrl = + JavaKeyStoreProvider.SCHEME_NAME + "://file" + jksPath.toUri(); + + File file = new File(testDir, "test.jks"); + file.delete(); + conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, ourUrl); + + // Set alias + String bindpassAlias = "bindpassAlias"; + conf.set(LdapGroupsMapping.BIND_PASSWORD_ALIAS_KEY, bindpassAlias); + + CredentialProvider provider = + CredentialProviderFactory.getProviders(conf).get(0); + char[] bindpass = "bindpass".toCharArray(); + + // Ensure that we get null when the key isn't there + assertNull(provider.getCredentialEntry(bindpassAlias)); + + // Create credential for the alias + provider.createCredentialEntry(bindpassAlias, bindpass); + provider.flush(); + + // Make sure we get back the right key + assertArrayEquals(bindpass, provider.getCredentialEntry( + bindpassAlias).getCredential()); + + LdapGroupsMapping mapping = new LdapGroupsMapping(); + Assert.assertEquals("bindpass", + mapping.getPasswordFromCredentialProviders(conf, bindpassAlias, "")); + + // Empty for an invalid alias + Assert.assertEquals("", mapping.getPasswordFromCredentialProviders( + conf, "invalid-alias", "")); + } + /** * Test that if the {@link LdapGroupsMapping#CONNECTION_TIMEOUT} is set in the * configuration, the LdapGroupsMapping connection will timeout by this value