HADOOP-9035. Generalize setup of LoginContext (daryn via bobby)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1410018 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Joseph Evans 2012-11-15 21:14:37 +00:00
parent 96f28d878e
commit 86ce5f6c91
4 changed files with 127 additions and 42 deletions

View File

@ -369,6 +369,8 @@ Release 2.0.3-alpha - Unreleased
HADOO-8998. set Cache-Control no-cache header on all dynamic content. (tucu) HADOO-8998. set Cache-Control no-cache header on all dynamic content. (tucu)
HADOOP-9035. Generalize setup of LoginContext (daryn via bobby)
OPTIMIZATIONS OPTIMIZATIONS
HADOOP-8866. SampleQuantiles#query is O(N^2) instead of O(N). (Andrew Wang HADOOP-8866. SampleQuantiles#query is O(N^2) instead of O(N). (Andrew Wang

View File

@ -294,14 +294,15 @@ public class Client {
} }
} }
AuthenticationMethod authentication;
if (token != null) { if (token != null) {
authMethod = AuthenticationMethod.TOKEN.getAuthMethod(); authentication = AuthenticationMethod.TOKEN;
} else if (UserGroupInformation.isSecurityEnabled()) { } else if (ticket != null) {
// eventually just use the ticket's authMethod authentication = ticket.getRealAuthenticationMethod();
authMethod = AuthMethod.KERBEROS; } else { // this only happens in lazy tests
} else { authentication = AuthenticationMethod.SIMPLE;
authMethod = AuthMethod.SIMPLE;
} }
authMethod = authentication.getAuthMethod();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Use " + authMethod + " authentication for protocol " LOG.debug("Use " + authMethod + " authentication for protocol "

View File

@ -17,7 +17,6 @@
*/ */
package org.apache.hadoop.security; package org.apache.hadoop.security;
import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION;
import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN; import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN;
import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN_DEFAULT; import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN_DEFAULT;
@ -133,7 +132,7 @@ public class UserGroupInformation {
} }
Principal user = null; Principal user = null;
// if we are using kerberos, try it out // if we are using kerberos, try it out
if (useKerberos) { if (isAuthenticationMethodEnabled(AuthenticationMethod.KERBEROS)) {
user = getCanonicalUser(KerberosPrincipal.class); user = getCanonicalUser(KerberosPrincipal.class);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("using kerberos user:"+user); LOG.debug("using kerberos user:"+user);
@ -191,8 +190,8 @@ public class UserGroupInformation {
static UgiMetrics metrics = UgiMetrics.create(); static UgiMetrics metrics = UgiMetrics.create();
/** Are the static variables that depend on configuration initialized? */ /** Are the static variables that depend on configuration initialized? */
private static boolean isInitialized = false; private static boolean isInitialized = false;
/** Should we use Kerberos configuration? */ /** The auth method to use */
private static boolean useKerberos; private static AuthenticationMethod authenticationMethod;
/** Server-side groups fetching service */ /** Server-side groups fetching service */
private static Groups groups; private static Groups groups;
/** Min time (in seconds) before relogin for Kerberos */ /** Min time (in seconds) before relogin for Kerberos */
@ -237,20 +236,7 @@ public class UserGroupInformation {
* @param conf the configuration to use * @param conf the configuration to use
*/ */
private static synchronized void initUGI(Configuration conf) { private static synchronized void initUGI(Configuration conf) {
AuthenticationMethod auth = SecurityUtil.getAuthenticationMethod(conf); authenticationMethod = SecurityUtil.getAuthenticationMethod(conf);
switch (auth) {
case SIMPLE:
case TOKEN:
useKerberos = false;
break;
case KERBEROS:
useKerberos = true;
break;
default:
throw new IllegalArgumentException("Invalid attribute value for " +
HADOOP_SECURITY_AUTHENTICATION +
" of " + auth);
}
try { try {
kerberosMinSecondsBeforeRelogin = 1000L * conf.getLong( kerberosMinSecondsBeforeRelogin = 1000L * conf.getLong(
HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN, HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN,
@ -288,8 +274,14 @@ public class UserGroupInformation {
* @return true if UGI is working in a secure environment * @return true if UGI is working in a secure environment
*/ */
public static boolean isSecurityEnabled() { public static boolean isSecurityEnabled() {
return !isAuthenticationMethodEnabled(AuthenticationMethod.SIMPLE);
}
@InterfaceAudience.Private
@InterfaceStability.Evolving
private static boolean isAuthenticationMethodEnabled(AuthenticationMethod method) {
ensureInitialized(); ensureInitialized();
return useKerberos; return (authenticationMethod == method);
} }
/** /**
@ -585,7 +577,7 @@ public class UserGroupInformation {
@InterfaceStability.Evolving @InterfaceStability.Evolving
public static UserGroupInformation getUGIFromTicketCache( public static UserGroupInformation getUGIFromTicketCache(
String ticketCache, String user) throws IOException { String ticketCache, String user) throws IOException {
if (!isSecurityEnabled()) { if (!isAuthenticationMethodEnabled(AuthenticationMethod.KERBEROS)) {
return getBestUGI(null, user); return getBestUGI(null, user);
} }
try { try {
@ -638,19 +630,12 @@ public class UserGroupInformation {
public synchronized public synchronized
static UserGroupInformation getLoginUser() throws IOException { static UserGroupInformation getLoginUser() throws IOException {
if (loginUser == null) { if (loginUser == null) {
ensureInitialized();
try { try {
Subject subject = new Subject(); Subject subject = new Subject();
LoginContext login; LoginContext login =
AuthenticationMethod authenticationMethod; newLoginContext(authenticationMethod.getLoginAppName(),
if (isSecurityEnabled()) {
authenticationMethod = AuthenticationMethod.KERBEROS;
login = newLoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME,
subject, new HadoopConfiguration()); subject, new HadoopConfiguration());
} else {
authenticationMethod = AuthenticationMethod.SIMPLE;
login = newLoginContext(HadoopConfiguration.SIMPLE_CONFIG_NAME,
subject, new HadoopConfiguration());
}
login.login(); login.login();
loginUser = new UserGroupInformation(subject); loginUser = new UserGroupInformation(subject);
loginUser.setLogin(login); loginUser.setLogin(login);
@ -675,6 +660,14 @@ public class UserGroupInformation {
return loginUser; return loginUser;
} }
@InterfaceAudience.Private
@InterfaceStability.Unstable
synchronized static void setLoginUser(UserGroupInformation ugi) {
// if this is to become stable, should probably logout the currently
// logged in ugi if it's different
loginUser = ugi;
}
/** /**
* Is this user logged in from a keytab file? * Is this user logged in from a keytab file?
* @return true if the credentials are from a keytab file. * @return true if the credentials are from a keytab file.
@ -1027,22 +1020,38 @@ public class UserGroupInformation {
public static enum AuthenticationMethod { public static enum AuthenticationMethod {
// currently we support only one auth per method, but eventually a // currently we support only one auth per method, but eventually a
// subtype is needed to differentiate, ex. if digest is token or ldap // subtype is needed to differentiate, ex. if digest is token or ldap
SIMPLE(AuthMethod.SIMPLE), SIMPLE(AuthMethod.SIMPLE,
KERBEROS(AuthMethod.KERBEROS), HadoopConfiguration.SIMPLE_CONFIG_NAME),
KERBEROS(AuthMethod.KERBEROS,
HadoopConfiguration.USER_KERBEROS_CONFIG_NAME),
TOKEN(AuthMethod.DIGEST), TOKEN(AuthMethod.DIGEST),
CERTIFICATE(null), CERTIFICATE(null),
KERBEROS_SSL(null), KERBEROS_SSL(null),
PROXY(null); PROXY(null);
private final AuthMethod authMethod; private final AuthMethod authMethod;
private final String loginAppName;
private AuthenticationMethod(AuthMethod authMethod) { private AuthenticationMethod(AuthMethod authMethod) {
this(authMethod, null);
}
private AuthenticationMethod(AuthMethod authMethod, String loginAppName) {
this.authMethod = authMethod; this.authMethod = authMethod;
this.loginAppName = loginAppName;
} }
public AuthMethod getAuthMethod() { public AuthMethod getAuthMethod() {
return authMethod; return authMethod;
} }
String getLoginAppName() {
if (loginAppName == null) {
throw new UnsupportedOperationException(
this + " login authentication is not supported");
}
return loginAppName;
}
public static AuthenticationMethod valueOf(AuthMethod authMethod) { public static AuthenticationMethod valueOf(AuthMethod authMethod) {
for (AuthenticationMethod value : values()) { for (AuthenticationMethod value : values()) {
if (value.getAuthMethod() == authMethod) { if (value.getAuthMethod() == authMethod) {
@ -1335,6 +1344,20 @@ public class UserGroupInformation {
return user.getAuthenticationMethod(); return user.getAuthenticationMethod();
} }
/**
* Get the authentication method from the real user's subject. If there
* is no real user, return the given user's authentication method.
*
* @return AuthenticationMethod in the subject, null if not present.
*/
public synchronized AuthenticationMethod getRealAuthenticationMethod() {
UserGroupInformation ugi = getRealUser();
if (ugi == null) {
ugi = this;
}
return ugi.getAuthenticationMethod();
}
/** /**
* Returns the authentication method of a ugi. If the authentication method is * Returns the authentication method of a ugi. If the authentication method is
* PROXY, returns the authentication method of the real user. * PROXY, returns the authentication method of the real user.

View File

@ -70,16 +70,75 @@ public class TestUserGroupInformation {
/** configure ugi */ /** configure ugi */
@BeforeClass @BeforeClass
public static void setup() { public static void setup() {
javax.security.auth.login.Configuration.setConfiguration(
new DummyLoginConfiguration());
}
@Before
public void setupUgi() {
conf = new Configuration(); conf = new Configuration();
conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL, conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL,
"RULE:[2:$1@$0](.*@HADOOP.APACHE.ORG)s/@.*//" + "RULE:[2:$1@$0](.*@HADOOP.APACHE.ORG)s/@.*//" +
"RULE:[1:$1@$0](.*@HADOOP.APACHE.ORG)s/@.*//" "RULE:[1:$1@$0](.*@HADOOP.APACHE.ORG)s/@.*//"
+ "DEFAULT"); + "DEFAULT");
UserGroupInformation.setConfiguration(conf); UserGroupInformation.setConfiguration(conf);
javax.security.auth.login.Configuration.setConfiguration( UserGroupInformation.setLoginUser(null);
new DummyLoginConfiguration());
} }
@After
public void resetUgi() {
UserGroupInformation.setLoginUser(null);
}
@Test
public void testSimpleLogin() throws IOException {
tryLoginAuthenticationMethod(AuthenticationMethod.SIMPLE, true);
}
@Test
public void testTokenLogin() throws IOException {
tryLoginAuthenticationMethod(AuthenticationMethod.TOKEN, false);
}
@Test
public void testProxyLogin() throws IOException {
tryLoginAuthenticationMethod(AuthenticationMethod.PROXY, false);
}
private void tryLoginAuthenticationMethod(AuthenticationMethod method,
boolean expectSuccess)
throws IOException {
SecurityUtil.setAuthenticationMethod(method, conf);
UserGroupInformation.setConfiguration(conf); // pick up changed auth
UserGroupInformation ugi = null;
Exception ex = null;
try {
ugi = UserGroupInformation.getLoginUser();
} catch (Exception e) {
ex = e;
}
if (expectSuccess) {
assertNotNull(ugi);
assertEquals(method, ugi.getAuthenticationMethod());
} else {
assertNotNull(ex);
assertEquals(UnsupportedOperationException.class, ex.getClass());
assertEquals(method + " login authentication is not supported",
ex.getMessage());
}
}
@Test
public void testGetRealAuthenticationMethod() {
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("user1");
ugi.setAuthenticationMethod(AuthenticationMethod.SIMPLE);
assertEquals(AuthenticationMethod.SIMPLE, ugi.getAuthenticationMethod());
assertEquals(AuthenticationMethod.SIMPLE, ugi.getRealAuthenticationMethod());
ugi = UserGroupInformation.createProxyUser("user2", ugi);
assertEquals(AuthenticationMethod.PROXY, ugi.getAuthenticationMethod());
assertEquals(AuthenticationMethod.SIMPLE, ugi.getRealAuthenticationMethod());
}
/** Test login method */ /** Test login method */
@Test @Test
public void testLogin() throws Exception { public void testLogin() throws Exception {