HADOOP-7853. multiple javax security configurations cause conflicts. (daryn via tucu)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1208751 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
94bf0dacba
commit
d8930feeae
|
@ -110,10 +110,6 @@ public class KerberosAuthenticator implements Authenticator {
|
|||
}
|
||||
}
|
||||
|
||||
static {
|
||||
javax.security.auth.login.Configuration.setConfiguration(new KerberosConfiguration());
|
||||
}
|
||||
|
||||
private URL url;
|
||||
private HttpURLConnection conn;
|
||||
private Base64 base64;
|
||||
|
@ -187,7 +183,8 @@ public class KerberosAuthenticator implements Authenticator {
|
|||
Subject subject = Subject.getSubject(context);
|
||||
if (subject == null) {
|
||||
subject = new Subject();
|
||||
LoginContext login = new LoginContext("", subject);
|
||||
LoginContext login = new LoginContext("", subject,
|
||||
null, new KerberosConfiguration());
|
||||
login.login();
|
||||
}
|
||||
Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
|
||||
|
|
|
@ -97,6 +97,9 @@ Trunk (unreleased changes)
|
|||
HADOOP-7833. Fix findbugs warnings in protobuf generated code.
|
||||
(John Lee via suresh)
|
||||
|
||||
HADOOP-7853. multiple javax security configurations cause conflicts.
|
||||
(daryn via tucu)
|
||||
|
||||
OPTIMIZATIONS
|
||||
|
||||
HADOOP-7761. Improve the performance of raw comparisons. (todd)
|
||||
|
|
|
@ -70,7 +70,7 @@ public class SecurityUtil {
|
|||
if (isOriginalTGT(t))
|
||||
return t;
|
||||
}
|
||||
throw new IOException("Failed to find TGT from current Subject");
|
||||
throw new IOException("Failed to find TGT from current Subject:"+current);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -118,18 +118,30 @@ public class UserGroupInformation {
|
|||
|
||||
@Override
|
||||
public boolean commit() throws LoginException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("hadoop login commit");
|
||||
}
|
||||
// if we already have a user, we are done.
|
||||
if (!subject.getPrincipals(User.class).isEmpty()) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("using existing subject:"+subject.getPrincipals());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Principal user = null;
|
||||
// if we are using kerberos, try it out
|
||||
if (useKerberos) {
|
||||
user = getCanonicalUser(KerberosPrincipal.class);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("using kerberos user:"+user);
|
||||
}
|
||||
}
|
||||
// if we don't have a kerberos user, use the OS user
|
||||
if (user == null) {
|
||||
user = getCanonicalUser(OS_PRINCIPAL_CLASS);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("using local user:"+user);
|
||||
}
|
||||
}
|
||||
// if we found the user, add our principal
|
||||
if (user != null) {
|
||||
|
@ -148,11 +160,17 @@ public class UserGroupInformation {
|
|||
|
||||
@Override
|
||||
public boolean login() throws LoginException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("hadoop login");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean logout() throws LoginException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("hadoop logout");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -220,26 +238,6 @@ public class UserGroupInformation {
|
|||
if (!(groups instanceof TestingGroups)) {
|
||||
groups = Groups.getUserToGroupsMappingService(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 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;
|
||||
}
|
||||
|
@ -398,12 +396,6 @@ public class UserGroupInformation {
|
|||
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)) {
|
||||
|
@ -414,13 +406,16 @@ public class UserGroupInformation {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private static LoginContext
|
||||
newLoginContext(String appName, Subject subject) throws LoginException {
|
||||
return new LoginContext(appName, subject, null, new HadoopConfiguration());
|
||||
}
|
||||
|
||||
private LoginContext getLogin() {
|
||||
return user.getLogin();
|
||||
}
|
||||
|
@ -476,10 +471,10 @@ public class UserGroupInformation {
|
|||
Subject subject = new Subject();
|
||||
LoginContext login;
|
||||
if (isSecurityEnabled()) {
|
||||
login = new LoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME,
|
||||
login = newLoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME,
|
||||
subject);
|
||||
} else {
|
||||
login = new LoginContext(HadoopConfiguration.SIMPLE_CONFIG_NAME,
|
||||
login = newLoginContext(HadoopConfiguration.SIMPLE_CONFIG_NAME,
|
||||
subject);
|
||||
}
|
||||
login.login();
|
||||
|
@ -503,6 +498,9 @@ public class UserGroupInformation {
|
|||
} catch (LoginException le) {
|
||||
throw new IOException("failure to login", le);
|
||||
}
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("UGI loginUser:"+loginUser);
|
||||
}
|
||||
}
|
||||
return loginUser;
|
||||
}
|
||||
|
@ -616,7 +614,7 @@ public class UserGroupInformation {
|
|||
long start = 0;
|
||||
try {
|
||||
login =
|
||||
new LoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject);
|
||||
newLoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject);
|
||||
start = System.currentTimeMillis();
|
||||
login.login();
|
||||
metrics.loginSuccess.add(System.currentTimeMillis() - start);
|
||||
|
@ -695,7 +693,7 @@ public class UserGroupInformation {
|
|||
login.logout();
|
||||
// login and also update the subject field of this instance to
|
||||
// have the new credentials (pass it to the LoginContext constructor)
|
||||
login = new LoginContext(
|
||||
login = newLoginContext(
|
||||
HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, getSubject());
|
||||
LOG.info("Initiating re-login for " + keytabPrincipal);
|
||||
start = System.currentTimeMillis();
|
||||
|
@ -744,7 +742,7 @@ public class UserGroupInformation {
|
|||
//login and also update the subject field of this instance to
|
||||
//have the new credentials (pass it to the LoginContext constructor)
|
||||
login =
|
||||
new LoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME,
|
||||
newLoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME,
|
||||
getSubject());
|
||||
LOG.info("Initiating re-login for " + getUserName());
|
||||
login.login();
|
||||
|
@ -781,7 +779,7 @@ public class UserGroupInformation {
|
|||
Subject subject = new Subject();
|
||||
|
||||
LoginContext login =
|
||||
new LoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject);
|
||||
newLoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject);
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
login.login();
|
||||
|
@ -1053,11 +1051,12 @@ public class UserGroupInformation {
|
|||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(getUserName());
|
||||
sb.append(" (auth:"+getAuthenticationMethod()+")");
|
||||
if (getRealUser() != null) {
|
||||
return getUserName() + " via " + getRealUser().toString();
|
||||
} else {
|
||||
return getUserName();
|
||||
sb.append(" via ").append(getRealUser().toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1132,6 +1131,7 @@ public class UserGroupInformation {
|
|||
* @return the value from the run method
|
||||
*/
|
||||
public <T> T doAs(PrivilegedAction<T> action) {
|
||||
logPrivilegedAction(subject, action);
|
||||
return Subject.doAs(subject, action);
|
||||
}
|
||||
|
||||
|
@ -1149,9 +1149,11 @@ public class UserGroupInformation {
|
|||
public <T> T doAs(PrivilegedExceptionAction<T> action
|
||||
) throws IOException, InterruptedException {
|
||||
try {
|
||||
logPrivilegedAction(subject, action);
|
||||
return Subject.doAs(subject, action);
|
||||
} catch (PrivilegedActionException pae) {
|
||||
Throwable cause = pae.getCause();
|
||||
LOG.error("PriviledgedActionException as:"+this+" cause:"+cause);
|
||||
if (cause instanceof IOException) {
|
||||
throw (IOException) cause;
|
||||
} else if (cause instanceof Error) {
|
||||
|
@ -1166,6 +1168,14 @@ public class UserGroupInformation {
|
|||
}
|
||||
}
|
||||
|
||||
private void logPrivilegedAction(Subject subject, Object action) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
// would be nice if action included a descriptive toString()
|
||||
String where = new Throwable().getStackTrace()[2].toString();
|
||||
LOG.debug("PrivilegedAction as:"+this+" from:"+where);
|
||||
}
|
||||
}
|
||||
|
||||
private void print() throws IOException {
|
||||
System.out.println("User: " + getUserName());
|
||||
System.out.print("Group Ids: ");
|
||||
|
|
|
@ -116,8 +116,9 @@ public class TestDoAsEffectiveUser {
|
|||
return UserGroupInformation.getCurrentUser();
|
||||
}
|
||||
});
|
||||
Assert.assertTrue(curUGI.toString().equals(
|
||||
PROXY_USER_NAME + " via " + REAL_USER_NAME));
|
||||
Assert.assertEquals(
|
||||
PROXY_USER_NAME + " (auth:PROXY) via " + REAL_USER_NAME + " (auth:SIMPLE)",
|
||||
curUGI.toString());
|
||||
}
|
||||
|
||||
@TokenInfo(TestTokenSelector.class)
|
||||
|
@ -174,7 +175,7 @@ public class TestDoAsEffectiveUser {
|
|||
}
|
||||
});
|
||||
|
||||
Assert.assertEquals(PROXY_USER_NAME + " via " + REAL_USER_NAME, retVal);
|
||||
Assert.assertEquals(PROXY_USER_NAME + " (auth:SIMPLE) via " + REAL_USER_NAME + " (auth:SIMPLE)", retVal);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
|
@ -216,7 +217,7 @@ public class TestDoAsEffectiveUser {
|
|||
}
|
||||
});
|
||||
|
||||
Assert.assertEquals(PROXY_USER_NAME + " via " + REAL_USER_NAME, retVal);
|
||||
Assert.assertEquals(PROXY_USER_NAME + " (auth:SIMPLE) via " + REAL_USER_NAME + " (auth:SIMPLE)", retVal);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
|
@ -446,7 +447,7 @@ public class TestDoAsEffectiveUser {
|
|||
}
|
||||
});
|
||||
//The user returned by server must be the one in the token.
|
||||
Assert.assertEquals(REAL_USER_NAME + " via SomeSuperUser", retVal);
|
||||
Assert.assertEquals(REAL_USER_NAME + " (auth:TOKEN) via SomeSuperUser (auth:SIMPLE)", retVal);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -498,7 +499,7 @@ public class TestDoAsEffectiveUser {
|
|||
}
|
||||
}
|
||||
});
|
||||
String expected = REAL_USER_NAME + " via SomeSuperUser";
|
||||
String expected = REAL_USER_NAME + " (auth:TOKEN) via SomeSuperUser (auth:SIMPLE)";
|
||||
Assert.assertEquals(retVal + "!=" + expected, expected, retVal);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package org.apache.hadoop.security;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.*;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
|
@ -32,9 +34,6 @@ import javax.security.auth.Subject;
|
|||
import javax.security.auth.login.AppConfigurationEntry;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.metrics2.MetricsRecordBuilder;
|
||||
import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
|
||||
|
@ -50,17 +49,32 @@ 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();
|
||||
/**
|
||||
* UGI should not use the default security conf, else it will collide
|
||||
* with other classes that may change the default conf. Using this dummy
|
||||
* class that simply throws an exception will ensure that the tests fail
|
||||
* if UGI uses the static default config instead of its own config
|
||||
*/
|
||||
private static class DummyLoginConfiguration extends
|
||||
javax.security.auth.login.Configuration
|
||||
{
|
||||
@Override
|
||||
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
|
||||
throw new RuntimeException("UGI is not using its own security conf!");
|
||||
}
|
||||
}
|
||||
|
||||
/** configure ugi */
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
Configuration conf = new Configuration();
|
||||
conf.set("hadoop.security.auth_to_local",
|
||||
"RULE:[2:$1@$0](.*@HADOOP.APACHE.ORG)s/@.*//" +
|
||||
"RULE:[1:$1@$0](.*@HADOOP.APACHE.ORG)s/@.*//"
|
||||
+ "DEFAULT");
|
||||
UserGroupInformation.setConfiguration(conf);
|
||||
javax.security.auth.login.Configuration.setConfiguration(
|
||||
new DummyLoginConfiguration());
|
||||
}
|
||||
|
||||
/** Test login method */
|
||||
|
@ -351,37 +365,6 @@ public class TestUserGroupInformation {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the case that UserGroupInformation.getCurrentUser()
|
||||
* is called when the AccessControlContext has a Subject associated
|
||||
|
|
Loading…
Reference in New Issue