diff --git a/CHANGES.txt b/CHANGES.txt index 4dd6acab90..f979b929e8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -416,6 +416,9 @@ Release 0.22.0 - Unreleased HADOOP-7082. Configuration.writeXML should not hold lock while outputting (todd) + HADOOP-7070. JAAS configuration should delegate unknown application names + to pre-existing configuration. (todd) + Release 0.21.1 - Unreleased IMPROVEMENTS diff --git a/src/java/org/apache/hadoop/security/UserGroupInformation.java b/src/java/org/apache/hadoop/security/UserGroupInformation.java index 497b57a329..16c20af321 100644 --- a/src/java/org/apache/hadoop/security/UserGroupInformation.java +++ b/src/java/org/apache/hadoop/security/UserGroupInformation.java @@ -245,9 +245,23 @@ private static synchronized void initUGI(Configuration conf) { // Set the configuration for JAAS to be the Hadoop configuration. // This is done here rather than a static initializer to avoid a // circular dependence. - javax.security.auth.login.Configuration.setConfiguration - (new HadoopConfiguration()); - + javax.security.auth.login.Configuration existingConfig = null; + try { + existingConfig = + javax.security.auth.login.Configuration.getConfiguration(); + } catch (SecurityException se) { + // If no security configuration is on the classpath, then + // we catch this exception, and we don't need to delegate + // to anyone + } + + if (existingConfig instanceof HadoopConfiguration) { + LOG.info("JAAS Configuration already set up for Hadoop, not re-installing."); + } else { + javax.security.auth.login.Configuration.setConfiguration( + new HadoopConfiguration(existingConfig)); + } + isInitialized = true; UserGroupInformation.conf = conf; } @@ -395,6 +409,12 @@ private static class HadoopConfiguration private static final AppConfigurationEntry[] KEYTAB_KERBEROS_CONF = new AppConfigurationEntry[]{KEYTAB_KERBEROS_LOGIN, HADOOP_LOGIN}; + private final javax.security.auth.login.Configuration parent; + + HadoopConfiguration(javax.security.auth.login.Configuration parent) { + this.parent = parent; + } + @Override public AppConfigurationEntry[] getAppConfigurationEntry(String appName) { if (SIMPLE_CONFIG_NAME.equals(appName)) { @@ -405,6 +425,8 @@ public AppConfigurationEntry[] getAppConfigurationEntry(String appName) { KEYTAB_KERBEROS_OPTIONS.put("keyTab", keytabFile); KEYTAB_KERBEROS_OPTIONS.put("principal", keytabPrincipal); return KEYTAB_KERBEROS_CONF; + } else if (parent != null) { + return parent.getAppConfigurationEntry(appName); } return null; } diff --git a/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java b/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java index 518fd52dcd..9a58f43350 100644 --- a/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java +++ b/src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.mockito.Mockito; import static org.mockito.Mockito.mock; import java.io.BufferedReader; @@ -31,6 +32,7 @@ import java.util.Collection; import java.util.List; +import javax.security.auth.login.AppConfigurationEntry; import javax.security.auth.login.LoginContext; import junit.framework.Assert; @@ -49,7 +51,11 @@ public class TestUserGroupInformation { final private static String[] GROUP_NAMES = new String[]{GROUP1_NAME, GROUP2_NAME, GROUP3_NAME}; + private static javax.security.auth.login.Configuration mockJaasConf; + static { + setupMockJaasParent(); + Configuration conf = new Configuration(); conf.set("hadoop.security.auth_to_local", "RULE:[2:$1@$0](.*@HADOOP.APACHE.ORG)s/@.*//" + @@ -346,4 +352,35 @@ public static void verifyLoginMetrics(int success, int failure) assertTrue(metrics.loginFailure.getPreviousIntervalAverageTime() > 0); } } + + /** + * Setup a JAAS Configuration that handles a fake app. + * This runs before UserGroupInformation has been initialized, + * so UGI picks up this Configuration as the parent. + */ + private static void setupMockJaasParent() { + javax.security.auth.login.Configuration existing = null; + try { + existing =javax.security.auth.login.Configuration.getConfiguration(); + assertFalse("setupMockJaasParent should run before the Hadoop " + + "configuration provider is installed.", + existing.getClass().getCanonicalName() + .startsWith("org.apache.hadoop")); + } catch (SecurityException se) { + // We get this if no configuration has been set. So it's OK. + } + + mockJaasConf = mock(javax.security.auth.login.Configuration.class); + Mockito.doReturn(new AppConfigurationEntry[] {}) + .when(mockJaasConf) + .getAppConfigurationEntry("foobar-app"); + javax.security.auth.login.Configuration.setConfiguration(mockJaasConf); + } + + @Test + public void testDelegateJaasConfiguration() throws Exception { + // This will throw if the Configuration doesn't have any entries + // for "foobar" + LoginContext login = new LoginContext("foobar-app"); + } }